diff --git a/AI-Agent-Standards/README.md b/AI-Agent-Standards/README.md new file mode 100644 index 0000000..38f8b02 --- /dev/null +++ b/AI-Agent-Standards/README.md @@ -0,0 +1,182 @@ +# AI Agent Documentation Standards + +Standar **Project Knowledge Preservation** untuk monorepo, dioptimalkan agar agent berikutnya lanjut kerja dengan **token minimal** (< 2000 token cold start). + +--- + +## Struktur + +``` +AI-Agent-Standards/ +├── README.md +├── recommendations.md +├── cursor-rule-project-handover.mdc +├── prompts/ +│ ├── end-of-session-handover.md +│ └── generate-ai-session-summary.md +├── templates/ +│ ├── handover-checklist.md +│ ├── repo/ +│ │ ├── AGENTS.md <- cold start (copy ke ROOT project) +│ │ ├── context-index.md <- peta domain (on-demand, boleh tebal) +│ │ ├── ai-session-summary.md <- rolling memory (max 80 baris) +│ │ ├── project-status.md +│ │ ├── todo.md +│ │ ├── changelog.md +│ │ ├── version.md +│ │ ├── server.md <- host/IP, docker, nginx, DB +│ │ ├── issues.md +│ │ ├── adr-template.md +│ │ ├── api/README.md +│ │ └── guide/README.md +│ └── workspace/ +└── examples/ +``` + +--- + +## Cold start (paling penting) + +``` +Workspace-Session.md (Active focus) # jika multi-project + -> {project}/AGENTS.md # ~200-400 token + -> {project}/docs/ai-session-summary.md # TL;DR + Lanjut + Jangan + -> STOP - mulai kerja +``` + +On-demand saja: todo, issues, api, guide, server.md, context-index, adr. + +**Jangan cold-start:** changelog penuh, version history, WORKLOG, development-log. + +**Rolling session memory = hanya** `docs/ai-session-summary.md`. +File kronologis lain = arsip. + +--- + +## Read budget + +| Tujuan | Baca maksimal | +|--------|----------------| +| Lanjut task yang sama | AGENTS + ai-session-summary | +| Ambil task baru | + todo.md (High) | +| Debug | + issues.md (ID terkait) | +| Deploy / koneksi / infra | + docs/server.md | +| Ubah API | + docs/api/ | +| Flow / prosedur | + docs/guide/ | +| Arsitektur | + docs/adr/ | +| Navigasi domain | + context-index (Zona B) | + +--- + +## Batas keras tulis + +| File | Batas | +|------|-------| +| `AGENTS.md` | ~40 baris | +| `ai-session-summary.md` | **80 baris / ~1500 token**; wajib TL;DR + Lanjut + Jangan | +| `Workspace-Session.md` | ~50-100 baris; wajib Active focus | + +--- + +## Struktur per subproject + +``` +{project}/ +├── AGENTS.md # WAJIB - cold start (root project) +├── .env.example # template URL/env (wajib) +└── docs/ + ├── ai-session-summary.md # rolling memory (OVERWRITE) + ├── context-index.md # peta (Zona A pointers + Zona B on-demand) + ├── project-status.md + ├── todo.md + ├── changelog.md + ├── version.md + ├── server.md # host/IP, runtime, DB (wajib) + ├── system-requirements.md # OS, runtime, tool (wajib) + ├── issues.md + ├── adr/ + ├── api/ # jika API / framework API + └── guide/ # wajib migration.md + guide lain +``` + +--- + +## Tier handover + +| Tier | Kapan | File | +|------|-------|------| +| **1 Minimal** | Perubahan kode/config | session (TL;DR) + todo + changelog + version (+ AGENTS jika perlu) | +| **Deploy** | Install ke device/server, rilis APK/binary, cutover prod | **Wajib** append `version.md` (bullet poin) + bump versi build config | +| **2 Relevan** | Kondisi terpenuhi | issues, adr, guide, server.md, system-requirements, .env.example, migration, status, context-index, api | +| **3 Monorepo** | Multi-project | Workspace-Session (Active focus) | + +--- + +## Single owner + +| Informasi | Owner | +|-----------|-------| +| Cold start / aturan kritis | `AGENTS.md` | +| Narasi sesi (rolling) | `ai-session-summary.md` | +| Priority | `todo.md` | +| Bug / RCA | `issues.md` | +| Changelog | `changelog.md` | +| Poin versi | `version.md` — **wajib append setiap deploy/naik versi** | +| API | `docs/api/` | +| Flow prosedur | `docs/guide/` | +| Server / IP / runtime / DB | `docs/server.md` | +| System requirements | `docs/system-requirements.md` | +| URL/env template | `.env.example` | +| Migrasi server/domain | `docs/guide/migration.md` | +| Peta domain | `context-index.md` | +| Lintas project | `Workspace-Session.md` | + +Pengetahuan penting, arsitektur, flow, inventori server, system requirements, migrasi **tidak boleh** hanya di chat. **No hardcoded URL.** + +--- + +## Setup subproject baru + +1. Copy `templates/repo/AGENTS.md` ke **root** project (sibling `docs/`) +2. Copy sisa `templates/repo/*` ke `{project}/docs/` +3. Isi AGENTS.md (pendek) dan context-index Zona A +4. Daftarkan di `Workspace-Context.md` + +## Quick command + +``` +Lakukan Project Knowledge Preservation sesuai standar di +AI-Agent-Standards/prompts/end-of-session-handover.md +``` + +## Cursor + +Salin `cursor-rule-project-handover.mdc` ke `.cursor/rules/` + +--- + +## No hardcoded URL + +- Semua URL/domain/host dari `.env` / env var / BuildConfig +- Template commit: `.env.example`; secret hanya di `.env` lokal (gitignore) +- Migrasi: update .env.example, server.md, guide/migration.md`r + +## Bootstrap project baru (salin ke agent) + +Prompt siap pakai: [prompts/bootstrap-new-project.md](prompts/bootstrap-new-project.md) + +Agent akan membaca template lalu membuat AGENTS.md + docs/ untuk satu atau lebih subproject, dan mendaftarkannya di Workspace-Context.md. + +Contoh: + +``` +Ikuti AI-Agent-Standards/prompts/bootstrap-new-project.md + +projects: + - path: lagercloud.com/billing + name: Billing + description: Service tagihan + stack: Python FastAPI + type: api + has_api: true +``` \ No newline at end of file diff --git a/AI-Agent-Standards/cursor-rule-project-handover.mdc b/AI-Agent-Standards/cursor-rule-project-handover.mdc new file mode 100644 index 0000000..009f04e --- /dev/null +++ b/AI-Agent-Standards/cursor-rule-project-handover.mdc @@ -0,0 +1,70 @@ +--- +description: Wajib jalankan Project Knowledge Preservation di akhir sesi atau sebelum commit/push +alwaysApply: true +--- + +# End of Session - Project Handover + +Sebelum menganggap pekerjaan selesai atau melakukan commit/push: + +1. Jalankan **Project Knowledge Preservation** sesuai standar +2. Standar lengkap: `AI-Agent-Standards/prompts/end-of-session-handover.md` + +## Tier (ringkas) + +**Tier 1 - Minimal** (per project yang berubah): +- OVERWRITE `docs/ai-session-summary.md` (max 80 baris; TL;DR + Lanjut + Jangan) +- UPDATE `docs/todo.md` ("Selesai sesi ini" overwrite) +- APPEND `docs/changelog.md` + `docs/version.md` (**wajib** jika deploy/naik versi — poin-poin perubahan, jangan skip) +- UPDATE `AGENTS.md` hanya jika aturan kritis berubah + +## Deploy / naik versi (wajib) + +Perubahan yang di-install ke device, server, atau production: +1. Bump versi di build config (SSOT numerik) +2. Append `docs/version.md` — bullet: apa berubah, fix/feature, QC/deploy note +3. Append `docs/changelog.md` (Keep a Changelog) +4. Tier 1 session summary + todo + +**Tier 2 - Jika relevan:** issues, ADR, guide, server.md, system-requirements.md, .env.example, guide/migration.md, project-status, context-index, api/ + +**Tier 3 - Monorepo:** OVERWRITE `Workspace-Session.md` (Active focus) + +## Single Owner + +- Cold start -> `AGENTS.md` +- Priority -> `todo.md` +- Bug/RCA -> `issues.md` +- Narasi sesi -> `ai-session-summary.md` +- Server/IP/DB -> `docs/server.md` +- System requirements -> `docs/system-requirements.md` +- Migrasi domain/server -> `docs/guide/migration.md` + `.env.example` +- Template URL/env -> `.env.example` (root project) +- Flow prosedur -> `docs/guide/` +- Arsitektur -> `docs/adr/` + +## No hardcoded URL + +- URL/domain/host:port dari env / `.env` / BuildConfig — **bukan** hardcode di source +- Migrasi: update `.env.example`, server.md, migration.md — minimal ubah kode +- Commit `.env.example` OK; `.env` dengan secret **tidak** + +## Aturan + +- Jangan simpan pengetahuan penting hanya di chat +- Jangan commit secret/credential +- Final Report ke user + +## Urutan Baca AI Berikutnya + +``` +Workspace-Session (Active focus) -> AGENTS.md -> ai-session-summary (TL;DR) -> STOP +``` + +On-demand: todo, issues, api, guide, server.md, system-requirements, migration, context-index, adr. + +## Slash Commands + +- `/handover` - full tiered preservation +- `/session-summary` - hanya ai-session-summary.md +- `/workspace-summary` - hanya Workspace-Session.md \ No newline at end of file diff --git a/AI-Agent-Standards/examples/example-repo-ai-session-summary.md b/AI-Agent-Standards/examples/example-repo-ai-session-summary.md new file mode 100644 index 0000000..1ed9442 --- /dev/null +++ b/AI-Agent-Standards/examples/example-repo-ai-session-summary.md @@ -0,0 +1,56 @@ +# AI Session Summary + + + +```yaml +session: 2026-07-03-ldap-login-fix +project: lagercloud.com/ldap +version: 1.2.0 +status: ready +next: Token revocation on logout +previous: 2026-07-01-ldap-migration +agent: Cursor +branch: feat/jwt-refresh +``` + +--- + +## TL;DR + +- Tambah endpoint JWT refresh token +- Perbaiki 401 loop saat token expired +- Update docs API auth + +--- + +## Lanjut dari sini + +1. Token revocation on logout +2. Integrasi refresh ke client Super App + +> Backlog: [todo.md](./todo.md) + +--- + +## Jangan + +- Jangan simpan refresh token di localStorage (pakai httpOnly cookie) +- Jangan revert error code TOKEN_EXPIRED di middleware + +--- + +## Detail + +### Bug fix + +| Bug | Root cause | Fix | Ref | +|-----|------------|-----|-----| +| 401 loop | Middleware throw unhandled | Return 401 + TOKEN_EXPIRED | [ISS-001](./issues.md) | + +### API + +| Method | Endpoint | Perubahan | +|--------|----------|-----------| +| POST | `/api/v1/auth/refresh` | Baru | + +**On-demand:** [../AGENTS.md](../AGENTS.md) | [todo.md](./todo.md) | [api/](./api/) \ No newline at end of file diff --git a/AI-Agent-Standards/examples/example-workspace-session.md b/AI-Agent-Standards/examples/example-workspace-session.md new file mode 100644 index 0000000..461494b --- /dev/null +++ b/AI-Agent-Standards/examples/example-workspace-session.md @@ -0,0 +1,58 @@ +# Workspace Session + + + +## Active focus + +- `lagercloud.com/ldap`: JWT refresh live -> next: token revocation +- `lagercloud.com/infra`: heartbeat 60s -> next: retry logic +- `lagercloud.com/Kotlin`: spec Device Request -> next: implement poll + +--- + +## Session Information + +| Field | Value | +|-------|-------| +| Tanggal | 2026-07-03 | +| Session ID | 2026-07-03-auth-agent-device | +| AI Agent | Cursor | + +--- + +## Executive Summary + +- LDAP: JWT refresh token +- infra: heartbeat timeout 60s +- Kotlin: spec Device Request + +--- + +## Project yang dikerjakan + +| Project | Path | Summary | Branch | Version | +|---------|------|---------|--------|---------| +| ldap | `lagercloud.com/ldap` | JWT refresh | feat/jwt-refresh | 1.2.0 | +| infra | `lagercloud.com/infra` | Heartbeat 60s | fix/heartbeat | 0.4.1 | +| Kotlin | `lagercloud.com/Kotlin` | Spec Device Request | docs/device-request | 1.1.2 | + +--- + +## Cross-Project Impact + +| Perubahan | Project | Dampak | +|-----------|---------|--------| +| JWT refresh | ldap | Client/agent perlu update auth | +| Heartbeat 60s | infra | Kotlin agent polling disesuaikan | + +--- + +## Referensi detail (on-demand) + +| Project | Cold start | Session | Version | +|---------|------------|---------|---------| +| ldap | [AGENTS.md](../lagercloud.com/ldap/AGENTS.md) | [session](../lagercloud.com/ldap/docs/ai-session-summary.md) | [version](../lagercloud.com/ldap/docs/version.md) | +| infra | [AGENTS.md](../lagercloud.com/infra/AGENTS.md) | [session](../lagercloud.com/infra/docs/ai-session-summary.md) | [version](../lagercloud.com/infra/docs/version.md) | +| Kotlin | [AGENTS.md](../lagercloud.com/Kotlin/AGENTS.md) | [session](../lagercloud.com/Kotlin/docs/ai-session-summary.md) | [version](../lagercloud.com/Kotlin/docs/version.md) | + +**Konteks stabil:** [Workspace-Context.md](../Workspace-Context.md) \ No newline at end of file diff --git a/AI-Agent-Standards/prompts/bootstrap-new-project.md b/AI-Agent-Standards/prompts/bootstrap-new-project.md new file mode 100644 index 0000000..89b45f0 --- /dev/null +++ b/AI-Agent-Standards/prompts/bootstrap-new-project.md @@ -0,0 +1,358 @@ +# Prompt: Bootstrap Project Docs dari AI-Agent-Standards + +> **Cara pakai:** Salin seluruh isi file ini ke chat agent, lalu isi blok **INPUT** di bawah (atau sebutkan path/nama project di pesan Anda). +> **Alias:** `/bootstrap-docs` +> **Tujuan:** Agent membaca template di `AI-Agent-Standards/` lalu **membuat** struktur dokumentasi standar untuk satu atau lebih subproject baru di monorepo. + +--- + +## INPUT (isi sebelum / saat menjalankan) + +Salin dan lengkapi: + +```yaml +projects: + - path: {path/relatif/dari/root monorepo} # contoh: lagercloud.com/my-service + name: {Nama Project} + description: {1-2 kalimat} + stack: {tech stack singkat} + type: app | api | library | infra | docs-only + has_api: true | false # true => buat docs/api/ + has_guide: true | false # true => buat docs/guide/ + version: 0.1.0 + servers: # opsional; wajib diisi jika sudah diketahui + - host: "{IP atau hostname}" + env: dev|staging|prod + role: app|db|reverse-proxy|worker + apps: # docker, nginx, IIS, Apache, SQL Server, PostgreSQL, ... + - name: "{service}" + kind: Docker|nginx|IIS|Apache|SQL Server|PostgreSQL|other + port: "{port}" + path_or_container: "{compose service / site / instance}" + critical_rules: # 3-7 bullet + - "{aturan kritis 1}" + - "{aturan kritis 2}" + initial_todos: # opsional + - priority: High + item: "{task}" +``` + +Jika user hanya memberi daftar path tanpa YAML, tanyakan field yang kurang **sekali**, lalu lanjut. Jangan tanya berulang. + +**Asumsi default jika tidak disebut:** +- `type: app` +- `has_api: false` (kecuali type = api atau nama/deskripsi menyebut API) +- `has_guide: false` +- `version: 0.1.0` +- `critical_rules`: minimal "No commit kecuali user minta", "No hardcoded URL/domain/IP — pakai .env.example", "Jangan commit .env", "Pengetahuan penting wajib ke docs bukan hanya chat" + +--- + +## Objective + +Untuk **setiap** project di INPUT: + +1. Baca template dari `AI-Agent-Standards/templates/repo/` +2. Buat struktur file sesuai standar +3. Isi field wajib (bukan meninggalkan semua placeholder `{...}`) +4. Daftarkan project di `Workspace-Context.md` (root monorepo) +5. Laporkan hasil ke user + +**Jangan** commit/push kecuali user meminta. +**Jangan** menimpa file yang sudah ada tanpa konfirmasi (kecuali user bilang "overwrite"). + +--- + +## Sumber template (WAJIB dibaca dulu) + +Baca file berikut sebelum menulis (cukup file ini + template yang akan di-copy): + +| File | Kegunaan | +|------|----------| +| `AI-Agent-Standards/README.md` | Ringkasan standar | +| `AI-Agent-Standards/templates/repo/AGENTS.md` | Cold start (ke ROOT project) | +| `AI-Agent-Standards/templates/repo/ai-session-summary.md` | Rolling session memory | +| `AI-Agent-Standards/templates/repo/context-index.md` | Peta domain | +| `AI-Agent-Standards/templates/repo/todo.md` | Priority | +| `AI-Agent-Standards/templates/repo/changelog.md` | Keep a Changelog | +| `AI-Agent-Standards/templates/repo/version.md` | Poin versi | +| `AI-Agent-Standards/templates/repo/issues.md` | Issues | +| `AI-Agent-Standards/templates/repo/project-status.md` | Status | +| `AI-Agent-Standards/templates/repo/adr-template.md` | ADR template | +| `AI-Agent-Standards/templates/repo/api/README.md` | Hanya jika has_api | +| `AI-Agent-Standards/templates/repo/guide/README.md` | Hanya jika has_guide | +| `AI-Agent-Standards/templates/repo/server.md` | Inventori server (selalu dibuat) | +| `templates/repo/system-requirements.md` | System requirements (selalu dibuat) | +| `templates/repo/.env.example` | Template URL/env (selalu dibuat) | +| `templates/repo/guide/migration.md` | Migrasi server/domain (selalu dibuat) | +| `Workspace-Context.md` | Daftarkan project + indeks server | + +Encoding: tulis file sebagai **UTF-8** (tanpa UTF-16). + +--- + +## Struktur yang harus dibuat (per project) + +``` +{path}/ +├── AGENTS.md # cold start +├── .env.example # template URL/env (WAJIB, commit OK) +└── docs/ + ├── ai-session-summary.md + ├── context-index.md + ├── project-status.md + ├── todo.md + ├── changelog.md + ├── version.md + ├── issues.md + ├── adr/ + │ └── 000-template.md # dari adr-template.md + ├── server.md # WAJIB - inventori host/IP/runtime/DB + ├── system-requirements.md # WAJIB - OS, runtime, tool minimum + ├── api/ # HANYA jika has_api: true + │ └── README.md + └── guide/ # WAJIB (minimal migration.md) + ├── README.md + └── migration.md # migrasi server/domain +``` + +### Mapping copy + +| Sumber (`AI-Agent-Standards/templates/repo/`) | Tujuan | +|-----------------------------------------------|--------| +| `AGENTS.md` | `{path}/AGENTS.md` | +| `ai-session-summary.md` | `{path}/docs/ai-session-summary.md` | +| `context-index.md` | `{path}/docs/context-index.md` | +| `project-status.md` | `{path}/docs/project-status.md` | +| `todo.md` | `{path}/docs/todo.md` | +| `changelog.md` | `{path}/docs/changelog.md` | +| `version.md` | `{path}/docs/version.md` | +| `issues.md` | `{path}/docs/issues.md` | +| `server.md` | `{path}/docs/server.md` | +| `system-requirements.md` | `{path}/docs/system-requirements.md` | +| `.env.example` | `{path}/.env.example` | +| `guide/migration.md` | `{path}/docs/guide/migration.md` | +| `adr-template.md` | `{path}/docs/adr/000-template.md` | +| `api/README.md` | `{path}/docs/api/README.md` (jika has_api) | +| `guide/README.md` | `{path}/docs/guide/README.md` | + +--- + +## Isi wajib (ganti placeholder) + +### 1. `{path}/AGENTS.md` (max ~40 baris) + +- Project path monorepo +- **Apa ini?** = `description` +- **Aturan kritis** = `critical_rules` (+ default jika kurang dari 3) +- Sertakan aturan **no hardcoded URL** + link `.env.example`, `docs/system-requirements.md`, `docs/guide/migration.md` +- Pertahankan urutan baca stop-early dari template + +### 2. `{path}/docs/context-index.md` + +**Zona A** wajib diisi: +- Nama, path, deskripsi/stack, tipe, versi, link AGENTS + session + todo +- Last updated = tanggal hari ini + +**Zona B:** biarkan tabel kosong atau minimal; hapus baris api/guide jika `has_api`/`has_guide` false. + +### 3. `{path}/docs/ai-session-summary.md` (max 80 baris) + +Isi sesi init: + +```yaml +session: {YYYY-MM-DD}-init +project: {path} +version: {version} +status: ready +next: {item High pertama dari initial_todos, atau "Isi todo dan mulai implementasi"} +agent: {nama agent jika diketahui, else Unknown} +branch: main +``` + +**TL;DR:** +- Bootstrap dokumentasi standar AI-Agent-Standards +- Project `{name}` siap dilanjutkan agent berikutnya + +**Lanjut dari sini:** +1. {dari initial_todos High, atau "Lengkapi spesifikasi / implementasi"} + +**Jangan:** +- Jangan simpan pengetahuan penting hanya di chat +- Jangan commit secret + +Hapus blok Detail jika tidak perlu. + +### 4. `{path}/docs/version.md` + +Entri pertama: + +```markdown +## [{version}] - {YYYY-MM-DD} + +- Bootstrap dokumentasi standar (AGENTS.md + docs/) +- Inisialisasi project `{name}` +``` + +### 5. `{path}/docs/changelog.md` + +Di `[Unreleased]` atau langsung versi: + +```markdown +## [{version}] - {YYYY-MM-DD} + +### Added +- Struktur dokumentasi standar AI-Agent-Standards +``` + +### 6. `{path}/docs/todo.md` + +- Masukkan `initial_todos` ke High/Medium/Low +- Seksi "Selesai (Sesi Ini)": bootstrap docs + +### 7. `{path}/docs/project-status.md` + +- Ringkasan = description +- Progress: Documentation = Done; implementasi sesuai status awal +- Next priority link ke todo.md + +### 8. `{path}/docs/issues.md` + +Biarkan struktur template (belum ada issue), ganti placeholder generik seminimal mungkin. + +### 9. `{path}/docs/server.md` (WAJIB) + +Salin dari `templates/repo/server.md`, lalu: + +- Isi **Project** path dan **Last updated** +- Jika INPUT punya `servers:`: isi tabel Host/Server, Aplikasi & Runtime, Database, Endpoint +- Isi **Mapping ke path project** dengan path monorepo project ini +- Jika server belum diketahui: biarkan tabel dengan satu baris placeholder dan catatan `TODO: isi saat infra diketahui` — **jangan hapus file** +- Credential location saja, **jangan** password/secret + +### 10. `{path}/docs/system-requirements.md` (WAJIB) + +- Isi tipe project, stack dari INPUT +- Tabel runtime/tool (JDK, Docker, Android Studio, SQL, dll.) — placeholder OK dengan TODO +- Seksi **Variabel URL & konfigurasi** — list variabel dari `.env.example` +- Cantumkan aturan no hardcode + +### 11. `{path}/.env.example` (WAJIB, root project) + +- Salin dari `templates/repo/.env.example` +- Sesuaikan nama variabel project (`API_BASE_URL`, dll.) +- Nilai = placeholder dev, **bukan** production secret +- Tambah komentar variabel khusus project (Android: `AGENT_API_BASE_URL`, dll.) + +### 12. `{path}/docs/guide/migration.md` (WAJIB) + +- Salin template; isi tabel inventori **jika** server/domain sudah diketahui +- Jika belum: biarkan checklist + catatan `TODO: isi saat migrasi pertama` +- Pastikan `guide/README.md` mengindeks migration.md + +--- + +## Update Workspace-Context.md (root monorepo) + +Untuk setiap project baru, **tambah baris** di tabel Project Aktif: + +| Repository | Path | Deskripsi | Status | Cold start | Context | +|------------|------|-----------|--------|------------|---------| +| `{name}` | `{path}/` | `{description}` | New | [`AGENTS.md`]({path}/AGENTS.md) | [`docs/context-index.md`]({path}/docs/context-index.md) | + +Tambah baris Quick Navigation: + +| Mulai kerja `{name}` | `{path}/AGENTS.md` -> `docs/ai-session-summary.md` | + +Jangan hapus project yang sudah ada. + +Jika ada seksi **Server Index** di `Workspace-Context.md`, tambah baris per host yang diketahui: + +| Host / IP | Project | Role | Runtime ringkas | Detail | +|-----------|---------|------|-----------------|--------| +| {ip} | `{path}` | {role} | {docker/nginx/SQL/...} | [server.md]({path}/docs/server.md) | + +Jika seksi belum ada, buat seksi `## Server Index (lintas project)` dengan tabel di atas (hanya indeks + link, detail di `docs/server.md`). + +**Jangan** overwrite `Workspace-Session.md` kecuali user minta (boleh sebut di laporan bahwa sesi berikutnya bisa menambahkan Active focus). + +--- + +## Aturan keamanan & kualitas + +- Encoding UTF-8 +- Tidak menulis secret/credential +- Tidak menghapus project/docs existing tanpa izin +- Jika `{path}` sudah punya `AGENTS.md` atau `docs/`: **stop dan tanya** overwrite / merge / skip +- Ikuti single owner: jangan menduplikasi backlog ke session summary +- Pengetahuan penting tidak boleh hanya di chat (sudah masuk docs lewat bootstrap ini) + +--- + +## Urutan eksekusi + +``` +1. Parse INPUT (semua project) +2. Baca template AI-Agent-Standards +3. Untuk tiap project: + a. Cek path belum ada konflik + b. Buat folder + c. Copy + isi file wajib +4. Update Workspace-Context.md +5. Final report +``` + +--- + +## Final Report (wajib ke user) + +Untuk setiap project: + +- Path dibuat +- File dibuat (daftar) +- has_api / has_guide +- server.md, system-requirements.md, .env.example, guide/migration.md +- Version awal +- Link cold start: `{path}/AGENTS.md` + +Workspace: + +- Baris yang ditambahkan ke `Workspace-Context.md` + +Langkah user berikutnya: + +``` +Buka {path}/AGENTS.md lalu docs/ai-session-summary.md untuk lanjut kerja. +Akhir sesi: ikuti AI-Agent-Standards/prompts/end-of-session-handover.md +``` + +--- + +## Contoh pemanggilan singkat (user) + +``` +Ikuti AI-Agent-Standards/prompts/bootstrap-new-project.md + +projects: + - path: lagercloud.com/billing + name: Billing + description: Service tagihan Training Center + stack: Python FastAPI + type: api + has_api: true + has_guide: false + - path: lagercloud.com/notify + name: Notify + description: Notifikasi WA/email + stack: Python + type: app + has_api: true + has_guide: true + - path: tools/report-cli + name: Report CLI + description: CLI laporan internal + stack: Node.js + type: app +``` + +Agent wajib membuat ketiga project sesuai template tanpa menunggu instruksi tambahan selain field yang benar-benar hilang. \ No newline at end of file diff --git a/AI-Agent-Standards/prompts/end-of-session-handover.md b/AI-Agent-Standards/prompts/end-of-session-handover.md new file mode 100644 index 0000000..0d8bf65 --- /dev/null +++ b/AI-Agent-Standards/prompts/end-of-session-handover.md @@ -0,0 +1,154 @@ +# Prompt AI Agent - End of Session Project Knowledge Preservation + +> **Trigger:** akhir sesi / sebelum commit-push. Alias: `/handover` +> **Workspace:** monorepo (satu git root, banyak subproject) + +--- + +## Objective + +Pindahkan pengetahuan sesi ke docs agar agent berikutnya lanjut dengan **token minimal** (< 2000 token cold start). + +Chat **bukan** penyimpanan pengetahuan. Catatan penting, arsitektur, flow, keputusan teknis **wajib** masuk docs (owner yang benar). + +--- + +## Scope + +Identifikasi subproject yang berubah. Project tanpa perubahan: skip. + +--- + +## Tier Handover + +### Tier 1 - Minimal (WAJIB jika ada perubahan kode/config) + +1. **OVERWRITE** `docs/ai-session-summary.md` + - Max 80 baris / ~1500 token + - Wajib: yaml + **TL;DR** + **Lanjut dari sini** + **Jangan** + - Detail opsional (omit-if-N/A) + - **Satu-satunya rolling session memory** - jangan andalkan WORKLOG/development-log + +2. **UPDATE** `docs/todo.md` + - Seksi "Selesai (Sesi Ini)" di-overwrite (bukan menumpuk) + +3. **APPEND** `docs/changelog.md` (Keep a Changelog saja) + +4. **APPEND** `docs/version.md` (poin-poin versi) — **wajib** jika deploy / naik versi / install ke device atau server; format bullet seperti entri semver yang ada; jangan overwrite entri lama + +5. **UPDATE** `AGENTS.md` (root project) **hanya jika** aturan kritis / pointer berubah + +### Tier 2 - Jika relevan + +| Kondisi | Aksi | +|---------|------| +| Bug / limitation | `docs/issues.md` | +| Keputusan arsitektur / flow sistem | `docs/adr/` | +| Flow / prosedur step-by-step | `docs/guide/` | +| Host/IP, runtime (Docker/nginx/IIS/Apache), DB, port berubah | `docs/server.md` | +| System requirement (OS, JDK, Docker, DB versi) berubah | `docs/system-requirements.md` | +| Migrasi server/domain / cutover URL | `docs/guide/migration.md` + `.env.example` | +| Variabel env/URL baru | `.env.example` (root project); kode baca env — **no hardcode** | +| Progress area | `docs/project-status.md` | +| Dokumen/struktur baru | `docs/context-index.md` | +| API berubah | `docs/api/` | + +### Tier 3 - Monorepo + +**OVERWRITE** `Workspace-Session.md`: +- Seksi **Active focus** di atas (1-3 baris per project) +- Tabel project + link session summary + version +- Cross-project impact +- Jangan duplikasi isi session summary + +--- + +## Single Owner + +| Informasi | Owner | +|-----------|-------| +| Cold start / aturan kritis | `AGENTS.md` (root project) | +| Narasi sesi (rolling) | `docs/ai-session-summary.md` | +| Priority / TODO | `docs/todo.md` | +| Bug / RCA | `docs/issues.md` | +| Changelog kategori | `docs/changelog.md` | +| Poin versi | `docs/version.md` | +| API | `docs/api/` | +| Step-by-step / flow prosedur | `docs/guide/` | +| Server / IP / runtime / DB | `docs/server.md` | +| System requirements | `docs/system-requirements.md` | +| Migrasi server/domain | `docs/guide/migration.md` | +| Template URL/env (dynamic) | `.env.example` (root) | +| Peta domain | `docs/context-index.md` (on-demand) | +| Lintas project sesi | `Workspace-Session.md` | + +**Arsip (bukan jalur baca wajib):** WORKLOG, development-log, history panjang. + +--- + +## Read budget (untuk AI berikutnya) + +| Tujuan | Baca maksimal | +|--------|----------------| +| Lanjut task yang sama | `AGENTS.md` + `ai-session-summary` (TL;DR/Lanjut/Jangan) | +| Ambil task baru | + `todo.md` (High saja) | +| Debug | + `issues.md` (ID terkait) | +| Ubah API | + `docs/api/` | +| Ikuti prosedur | + `docs/guide/` | +| Deploy / debug koneksi / infra | + `docs/server.md` | +| Migrasi / ganti domain | + `docs/guide/migration.md` + `.env.example` | +| Setup tool chain | + `docs/system-requirements.md` | +| Keputusan arsitektur | + `docs/adr/` terkait | +| Navigasi domain | + `context-index.md` Zona B | + +**Urutan cold start:** + +``` +Workspace-Session.md (jika multi-project; baca Active focus dulu) + -> {project}/AGENTS.md + -> {project}/docs/ai-session-summary.md + -> STOP - mulai kerja +``` + +Target: **< 2000 token** sebelum coding. + + +--- + +## No hardcoded URL (wajib) + +- Semua **URL, domain, base path, host:port** di aplikasi harus dari **environment** atau config yang dibaca saat runtime/build (.env, env var, BuildConfig, gradle.properties). +- **Dilarang** hardcode di source code kecuali unit test mock atau .env.example placeholder. +- Saat migrasi domain/server: ubah .env / server config + update .env.example, server.md, guide/migration.md — **bukan** scatter edit URL di banyak file kode. +- Android/Kotlin: base URL lewat BuildConfig/flavor, bukan string literal di Activity/Service. +- Commit: .env.example boleh; .env dengan secret **tidak**. + +--- + +## Knowledge compression + +- Ringkas; omit-if-N/A; referensi jangan salin +- **Harus masuk docs:** solusi bug, troubleshooting, config, deploy, keputusan teknis, arsitektur, flow, **system requirements**, **inventori server**, **langkah migrasi server/domain**, root cause, workaround, dependency, versi +- **Jangan:** secret, log mentah, chat verbatim, info yang sudah di kode + +--- + +## Validation + +Lihat `templates/handover-checklist.md`. + +Minimal: +- [ ] Tier 1 lengkap +- [ ] Session summary punya TL;DR + Lanjut + Jangan, <= 80 baris +- [ ] Tidak ada pengetahuan penting hanya di chat +- [ ] Tidak ada secret di diff + +--- + +## Git + +Commit Conventional Commits hanya jika user meminta. Push hanya jika diminta. + +## Final Report + +Project, tier, file, version, TODO/issue/ADR baru, ringkasan, next steps. \ No newline at end of file diff --git a/AI-Agent-Standards/prompts/generate-ai-session-summary.md b/AI-Agent-Standards/prompts/generate-ai-session-summary.md new file mode 100644 index 0000000..67cd771 --- /dev/null +++ b/AI-Agent-Standards/prompts/generate-ai-session-summary.md @@ -0,0 +1,63 @@ +# AI Agent Command - Generate AI Session Summary + +> **Trigger:** `/session-summary` +> **Target file:** `docs/ai-session-summary.md` +> **Strategi:** OVERWRITE (bukan append) +> **Batas keras:** max 80 baris / ~1500 token +> **Satu-satunya rolling session memory** per project + +--- + +## Tujuan + +Overwrite `docs/ai-session-summary.md` agar agent berikutnya lanjut kerja dari **TL;DR + Lanjut dari sini + Jangan** tanpa baca docs lain. + +Target cold-start total (AGENTS + session): **< 2000 token**. + +--- + +## Aturan tulis + +1. File selalu di-overwrite +2. **Wajib di atas:** yaml metadata + TL;DR + Lanjut dari sini + Jangan +3. Blok **Detail** hanya jika perlu; hapus jika TL;DR cukup +4. Omit seksi kosong - jangan isi N/A +5. Max 80 baris total +6. "Catatan untuk AI berikutnya" max 5 bullet +7. Jangan salin changelog / daftar file / backlog todo / RCA issues +8. Jangan mengandalkan WORKLOG atau development-log sebagai pengganti file ini + +--- + +## Struktur wajib + +```yaml +session: ... +project: ... +version: ... +status: ready|blocked|in-progress +next: ... +``` + +## TL;DR +- max 5 bullet + +## Lanjut dari sini +1. ... +2. ... + +## Jangan +- max 5 bullet + +## Detail (opsional) +- Perubahan material, feature, bug, config/api/db, catatan + +Template: `templates/repo/ai-session-summary.md` + +--- + +## Setelah selesai + +1. Tier 1 lain: todo.md, changelog.md, version.md +2. AGENTS.md hanya jika aturan kritis berubah +3. Multi-project: Workspace-Session.md (sertakan Active focus) \ No newline at end of file diff --git a/AI-Agent-Standards/recommendations.md b/AI-Agent-Standards/recommendations.md new file mode 100644 index 0000000..41810dc --- /dev/null +++ b/AI-Agent-Standards/recommendations.md @@ -0,0 +1,50 @@ +# Rekomendasi Standar Dokumentasi AI + +Status: **diadopsi ke template** (termasuk optimasi token 2026-07-04). + +--- + +## Diadopsi + +1. Session ID + yaml metadata di session summary +2. STRATEGY badge +3. Tier handover (Minimal / Relevan / Monorepo) +4. Single owner +5. Keep a Changelog saja +6. omit-if-N/A +7. todo "Selesai sesi ini" overwrite +8. context-index boleh tebal, berlapis (Zona A / Zona B) +9. Monorepo model +10. docs/api/ dan docs/guide/ +11. docs/version.md — **wajib append** setiap deploy / naik versi (poin-poin perubahan) +12. Pengetahuan penting tidak boleh hanya di chat +13. **AGENTS.md cold start** (root project, max ~40 baris) +14. **Session summary:** TL;DR + Lanjut + Jangan; max 80 baris +15. **Satu rolling memory:** hanya ai-session-summary; WORKLOG/development-log = arsip +16. **Read budget** + urutan stop-early (< 2000 token) +17. **Workspace-Session Active focus** +18. **docs/server.md** - inventori host/IP, runtime, port +19. **docs/system-requirements.md** - OS, runtime, tool minimum +20. **.env.example** - template URL/env (dynamic, no hardcode) +21. **docs/guide/migration.md** - migrasi server/domain + checklist cutover + +--- + +## Opsional (belum diwajibkan) + +- `docs/.handover-meta.json` untuk CI +- Pre-commit hook otomatis: kode berubah => session summary + version harus berubah +- Wiring slash commands per agent tool + +--- + +## Estimasi token cold start + +| Skenario | File | Estimasi | +|----------|------|----------| +| Lanjut task (satu project) | AGENTS + session (TL;DR) | **~700-2000** | +| Multi-project | Workspace-Session Active focus + AGENTS + session | ~1000-2500 | +| Ambil task baru | + todo High | +200-500 | +| Debug | + issues ID | +300-800 | + +Target: **< 2000 token** sebelum coding pada jalur panas. \ No newline at end of file diff --git a/AI-Agent-Standards/templates/handover-checklist.md b/AI-Agent-Standards/templates/handover-checklist.md new file mode 100644 index 0000000..48b91ce --- /dev/null +++ b/AI-Agent-Standards/templates/handover-checklist.md @@ -0,0 +1,53 @@ +# Handover Checklist + + + +## Tier 1 - Minimal + +Per project yang berubah: + +- [ ] `docs/ai-session-summary.md` di-**overwrite** + - [ ] yaml metadata ada + - [ ] **TL;DR** (max 5 bullet) + - [ ] **Lanjut dari sini** (1-3 item) + - [ ] **Jangan** (max 5 bullet) + - [ ] Total <= 80 baris; Detail di-omit jika tidak perlu +- [ ] `docs/todo.md` diupdate; "Selesai (Sesi Ini)" di-overwrite +- [ ] `docs/changelog.md` di-append (Keep a Changelog) +- [ ] `docs/version.md` di-append (poin-poin) — **wajib** jika deploy / naik versi / install ke device-server +- [ ] Versi build config di-bump (gradle, package.json, dll.) selaras entri `version.md` +- [ ] `AGENTS.md` diupdate **hanya jika** aturan kritis berubah + +## Tier 2 - Jika relevan + +- [ ] `docs/issues.md` +- [ ] `docs/adr/` (arsitektur / flow sistem) +- [ ] `docs/guide/` (prosedur step-by-step) +- [ ] `docs/project-status.md` +- [ ] `docs/context-index.md` +- [ ] `docs/api/` +- [ ] `docs/server.md` (host/IP, runtime, DB berubah) +- [ ] `docs/system-requirements.md` (OS/runtime/tool berubah) +- [ ] `.env.example` + kode **no hardcoded URL** (domain/server migrasi) +- [ ] `docs/guide/migration.md` (jika migrasi/cutover) + +## Tier 3 - Monorepo + +- [ ] `Workspace-Session.md` di-overwrite +- [ ] Seksi **Active focus** diisi +- [ ] Link session summary + version per project +- [ ] Cross-project impact + +## Quality + +- [ ] Rolling memory hanya di ai-session-summary (bukan WORKLOG sebagai pengganti) +- [ ] Tidak ada pengetahuan penting hanya di chat +- [ ] Tidak ada duplikasi owner (todo/issues/session) +- [ ] Tidak ada secret / log mentah panjang +- [ ] Agent berikutnya bisa stop setelah AGENTS + session summary + +## Git + +- [ ] Review perubahan +- [ ] Conventional Commit (jika diminta) +- [ ] Final report ke user \ No newline at end of file diff --git a/AI-Agent-Standards/templates/repo/.env.example b/AI-Agent-Standards/templates/repo/.env.example new file mode 100644 index 0000000..f5d6f34 --- /dev/null +++ b/AI-Agent-Standards/templates/repo/.env.example @@ -0,0 +1,41 @@ +# .env.example — Template konfigurasi (AMAN di-commit) +# Copy ke .env di root project yang sama (JANGAN commit .env) +# Semua URL/host/domain aplikasi HARUS dibaca dari variabel ini (no hardcode di kode) + +# --- Environment --- +APP_ENV=development +# development | staging | production + +# --- Public URLs (ubah saat migrasi domain) --- +APP_URL=https://app-dev.example.com +API_BASE_URL=https://api-dev.example.com +# API_BASE_URL=http://10.0.0.1:8055 + +# --- Auth / SSO (jika ada) --- +# AUTH_ISSUER_URL= +# OIDC_REDIRECT_URI= + +# --- Database (host saja di docs; credential di .env lokal) --- +DB_HOST=127.0.0.1 +DB_PORT=5432 +DB_NAME=myapp +DB_USER= +DB_PASSWORD= + +# --- Redis / cache (opsional) --- +# REDIS_URL=redis://127.0.0.1:6379/0 + +# --- Internal service (monorepo) --- +# LDAP_API_URL= +# AGENT_API_URL= + +# --- Android / build-time (alternatif jika tidak pakai .env runtime) --- +# AGENT_API_BASE_URL=https://agent-dev.example.com + +# --- Logging / debug --- +# LOG_LEVEL=info +# DEBUG=false + +# Dokumentasi variabel: docs/system-requirements.md +# Migrasi server/domain: docs/guide/migration.md +# Inventori host: docs/server.md \ No newline at end of file diff --git a/AI-Agent-Standards/templates/repo/AGENTS.md b/AI-Agent-Standards/templates/repo/AGENTS.md new file mode 100644 index 0000000..6aa9912 --- /dev/null +++ b/AI-Agent-Standards/templates/repo/AGENTS.md @@ -0,0 +1,60 @@ +# AGENTS.md - Cold Start + + + + +> Project: `{path/relatif/dari/root monorepo}` +> Sesi terakhir: [docs/ai-session-summary.md](./docs/ai-session-summary.md) +> Peta lengkap (on-demand): [docs/context-index.md](./docs/context-index.md) +> Env template: [.env.example](./.env.example) + +## Apa ini? + +{1-2 kalimat: apa project ini dan perannya di monorepo} + +## Aturan kritis + +- {aturan 1 - mis. tidak akses DB langsung} +- **No hardcoded URL/domain/IP** — baca dari `.env` / env var / BuildConfig / config +- Copy `.env.example` -> `.env` lokal; jangan commit `.env` berisi secret +- No commit kecuali user minta eksplisit +- **Deploy / rilis:** naikkan versi di build config + **wajib append** [docs/version.md](./docs/version.md) (poin-poin perubahan) +- {aturan lain - max 7 bullet total} + +## Lanjut kerja (urutan baca) + +``` +1. AGENTS.md <- Anda di sini (~200-400 token) +2. docs/ai-session-summary.md <- TL;DR + Lanjut + Jangan +3. STOP - mulai kerja +4. On-demand: + - docs/todo.md + - docs/issues.md + - docs/api/ + - docs/guide/migration.md (pindah server/domain) + - docs/system-requirements.md + - docs/server.md + - .env.example + - docs/context-index.md +``` + +**Jangan cold start:** changelog penuh, WORKLOG, development-log. + +**Rolling session memory = hanya** `docs/ai-session-summary.md`. + +## Pointer cepat + +| Butuh | Buka | +|-------|------| +| Priority | [docs/todo.md](./docs/todo.md) | +| Versi / deploy | [docs/version.md](./docs/version.md) | +| Bug / RCA | [docs/issues.md](./docs/issues.md) | +| API | [docs/api/](./docs/api/) | +| Migrasi server/domain | [docs/guide/migration.md](./docs/guide/migration.md) | +| System requirements | [docs/system-requirements.md](./docs/system-requirements.md) | +| Server / infra | [docs/server.md](./docs/server.md) | +| Variabel URL/env | [.env.example](./.env.example) | + +## Multi-project + +`Workspace-Session.md` -> `AGENTS.md` project terkait. \ No newline at end of file diff --git a/AI-Agent-Standards/templates/repo/adr-template.md b/AI-Agent-Standards/templates/repo/adr-template.md new file mode 100644 index 0000000..eb35b68 --- /dev/null +++ b/AI-Agent-Standards/templates/repo/adr-template.md @@ -0,0 +1,50 @@ +# ADR-{NNN}: {Judul Keputusan} + + + +**Owner:** keputusan arsitektur (context, decision, alternatives, consequences). +Simpan di `docs/adr/NNN-judul-singkat.md`. + +| Field | Value | +|-------|-------| +| Status | Proposed / Accepted / Deprecated / Superseded | +| Date | {YYYY-MM-DD} | +| Author | {AI Agent / Developer} | +| Session | {session-id} | +| Version | {x.y.z jika terkait rilis} | + +--- + +## Context + +{Masalah atau situasi yang memerlukan keputusan} + +--- + +## Decision + +{Keputusan yang diambil} + +--- + +## Alternatives Considered + +| Alternatif | Pro | Con | +|------------|-----|-----| +| | | | + +--- + +## Consequences + +**Positif:** +- + +**Negatif / Trade-off:** +- + +--- + +## References + +- {link ke issue, PR, docs terkait} \ No newline at end of file diff --git a/AI-Agent-Standards/templates/repo/ai-session-summary.md b/AI-Agent-Standards/templates/repo/ai-session-summary.md new file mode 100644 index 0000000..6e70050 --- /dev/null +++ b/AI-Agent-Standards/templates/repo/ai-session-summary.md @@ -0,0 +1,78 @@ +# AI Session Summary + + + + + +**Jangan duplikasi:** changelog/version (daftar file), todo (backlog), issues (RCA penuh), project-status. + +File kronologis lain (WORKLOG, development-log) **bukan** pengganti file ini dan **bukan** jalur baca wajib. + +--- + +```yaml +session: {YYYY-MM-DD-judul-singkat} +project: {path/relatif} +version: {x.y.z} +status: ready|blocked|in-progress +next: {satu baris prioritas langsung} +previous: {session-id sebelumnya atau N/A} +agent: {Cursor/Cline/dll} +branch: {branch} +``` + +--- + +## TL;DR + +- {max 5 bullet - apa yang dikerjakan dan hasilnya} +- + +--- + +## Lanjut dari sini + +1. {prioritas langsung sesi berikutnya} +2. {opsional} +3. {opsional} + +> Backlog penuh: [todo.md](./todo.md) + +--- + +## Jangan + +- {pitfall / regresi / hal yang tidak boleh diulang - max 5 bullet} +- + +--- + +## Detail (hanya jika perlu) + + + +### Perubahan material + +> [changelog.md](./changelog.md) | [version.md](./version.md) + +- {1-5 bullet dampak - bukan path file} + +### Feature + +- {fitur} + +### Bug fix + +| Bug | Root cause | Fix | Ref | +|-----|------------|-----|-----| +| | | | [ISS-NNN](./issues.md) | + +### Config / infra / API / DB + +- {ringkas; API detail di [api/](./api/); server/IP/runtime di [server.md](./server.md)} + +### Catatan untuk AI berikutnya + +- {hanya info yang tidak ada di docs lain - max 5 bullet} + +**On-demand:** [context-index.md](./context-index.md) | [todo.md](./todo.md) | [issues.md](./issues.md) \ No newline at end of file diff --git a/AI-Agent-Standards/templates/repo/api/README.md b/AI-Agent-Standards/templates/repo/api/README.md new file mode 100644 index 0000000..a8d0159 --- /dev/null +++ b/AI-Agent-Standards/templates/repo/api/README.md @@ -0,0 +1,44 @@ +# API Documentation + + + +**Owner:** kontrak API (endpoint, auth, request/response, error code). +Session summary hanya ringkas perubahan — detail tetap di sini. + +## Indeks Endpoint + +| Method | Path | Deskripsi | Auth | Doc | +|--------|------|-----------|------|-----| +| | | | | [nama.md](./nama.md) | + +## Konvensi + +- Satu file per resource/domain, atau satu file OpenAPI jika lebih cocok. +- Breaking change wajib dicatat di [../changelog.md](../changelog.md) dan [../version.md](../version.md). +- Contoh request/response tanpa credential nyata. + +## Template Endpoint + +### `{METHOD} {/path}` + +**Deskripsi:** {apa yang dilakukan} + +**Auth:** {none / bearer / api-key / session} + +**Request:** + +```json +{} +``` + +**Response 200:** + +```json +{} +``` + +**Error:** + +| Code | Meaning | +|------|---------| +| | | \ No newline at end of file diff --git a/AI-Agent-Standards/templates/repo/changelog.md b/AI-Agent-Standards/templates/repo/changelog.md new file mode 100644 index 0000000..65d2399 --- /dev/null +++ b/AI-Agent-Standards/templates/repo/changelog.md @@ -0,0 +1,46 @@ +# Changelog + + + +Format: [Keep a Changelog](https://keepachangelog.com/). +Satu format saja — jangan campur entri per-sesi terpisah. + +**Owner:** riwayat perubahan permanen per kategori (Added / Changed / Fixed / Removed / Deprecated / Security). +Session summary **tidak** mengulang daftar file atau entri changelog — cukup link ke sini. + +Versi rilis berpoin: lihat [version.md](./version.md). + +--- + +## [Unreleased] + +### Added +- + +### Changed +- + +### Fixed +- + +### Removed +- + +### Deprecated +- + +### Security +- + +--- + +## [x.y.z] - {YYYY-MM-DD} + +### Added +- {fitur baru} + +### Fixed +- {bug fix} + +### Changed +- {perubahan perilaku} \ No newline at end of file diff --git a/AI-Agent-Standards/templates/repo/context-index.md b/AI-Agent-Standards/templates/repo/context-index.md new file mode 100644 index 0000000..2bb73e9 --- /dev/null +++ b/AI-Agent-Standards/templates/repo/context-index.md @@ -0,0 +1,141 @@ +# Context Index + + + + +> Multi-project: `Workspace-Session.md` (root) -> `{project}/AGENTS.md` -> `docs/ai-session-summary.md` -> **STOP**. +> File ini hanya jika perlu navigasi domain. + +Boleh tebal (spec, architecture, parent/sibling, checklist) seperti pola Kotlin. +Tetap **indeks + link**, bukan salinan isi dokumen lain. + +--- + +## Zona A - Always-read pointers + +| Item | Value | +|------|-------| +| Nama | {REPO_NAME} | +| Path monorepo | `{path/relatif/dari/root}` | +| Cold start | [../AGENTS.md](../AGENTS.md) | +| Sesi terakhir | [ai-session-summary.md](./ai-session-summary.md) | +| Priority aktif | [todo.md](./todo.md) | +| Server / infra | [server.md](./server.md) | +| System requirements | [system-requirements.md](./system-requirements.md) | +| Env / URL template | [../.env.example](../.env.example) | +| Versi | {x.y.z} - [version.md](./version.md) | +| Stack | {TECH_STACK} | +| Tipe | {app / api / library / infra / docs-only} | +| Last updated | {YYYY-MM-DD} | + +**Rolling session memory:** hanya [ai-session-summary.md](./ai-session-summary.md). +Arsip (jangan cold-start): WORKLOG, development-log, changelog penuh, version history penuh. + +--- + +## Zona B - On-demand map + +> Baca baris di bawah **hanya jika tugas menyentuh area tersebut**. + +### Dokumentasi inti + +| Dokumen | Isi | Kapan baca | +|---------|-----|------------| +| [ai-session-summary.md](./ai-session-summary.md) | Narasi sesi (overwrite) | Setelah AGENTS | +| [todo.md](./todo.md) | Priority aktif | Ambil / ubah task | +| [project-status.md](./project-status.md) | Progress area | Butuh status luas | +| [issues.md](./issues.md) | Bug / RCA | Debug | +| [changelog.md](./changelog.md) | Keep a Changelog | Audit riwayat | +| [version.md](./version.md) | Poin per versi | Cek versi / rilis | +| [server.md](./server.md) | Host/IP, runtime, DB, port | Deploy / debug koneksi / ubah infra | +| [system-requirements.md](./system-requirements.md) | OS, runtime, tool minimum | Setup / upgrade / migrasi | +| [guide/migration.md](./guide/migration.md) | Migrasi server/domain | Cutover URL/env | +| [../.env.example](../.env.example) | Variabel URL/host (template) | Konfigurasi dynamic URL | +| [adr/](./adr/) | Keputusan arsitektur | Ubah arsitektur | + +### API dan guide (jika berlaku) + +| Kondisi | Path | Kapan baca | +|---------|------|------------| +| Project API / framework API | [api/](./api/) | Ubah / konsumsi endpoint | +| Prosedur step-by-step | [guide/](./guide/) | Ikuti runbook / setup | + +### Spesifikasi / architecture + +| Dokumen | Path | Kapan baca | +|---------|------|------------| +| | | | + +### Environment / development + +| Dokumen | Path | Kapan baca | +|---------|------|------------| +| | | | + +### Parent / sibling (monorepo) + +| Dokumen | Path | Kapan baca | +|---------|------|------------| +| | | | + +--- + +## Struktur kode + +``` +{root-project}/ +├── AGENTS.md # cold start (wajib) +├── .env.example # template URL/env (commit OK) +├── docs/ # dokumentasi standar +└── {modul}/ # {deskripsi} +``` + +--- + +## Dependency + +| Project / Service | Relasi | +|-------------------|--------| +| | | + +--- + +## Environment + +> Detail inventori server: **[server.md](./server.md)** (single owner). + +| Env | URL / Host | Catatan | +|-----|------------|---------| +| dev | | ringkas; detail di server.md | + +Credential: {lokasi vault/env} - jangan simpan secret di docs. + +--- + +## Aturan kritis AI + +> Duplikat singkat dari AGENTS.md - detail aturan di AGENTS.md. + +- Minimal diff - fokus scope project ini. +- No commit kecuali user minta. +- Single owner: priority -> todo; bug -> issues; sesi -> ai-session-summary. +- Perubahan material -> version.md + changelog.md. +- Host/IP/runtime/DB berubah -> update server.md. +- Tool/OS requirement berubah -> update system-requirements.md. +- Migrasi server/domain -> update guide/migration.md, .env.example, server.md; **no hardcoded URL** di kode. +- Pengetahuan penting tidak boleh hanya di chat. +- Implementasi tanpa Tier 1 handover = belum selesai. + +--- + +## Checklist + +### Sebelum implementasi +- [ ] Baca AGENTS.md + ai-session-summary (TL;DR / Lanjut / Jangan) +- [ ] todo / issues hanya jika perlu + +### Setelah implementasi (Tier 1) +- [ ] Overwrite ai-session-summary (max 80 baris; TL;DR wajib) +- [ ] Update todo.md +- [ ] Append changelog.md + version.md +- [ ] Update AGENTS.md hanya jika aturan kritis berubah \ No newline at end of file diff --git a/AI-Agent-Standards/templates/repo/guide/README.md b/AI-Agent-Standards/templates/repo/guide/README.md new file mode 100644 index 0000000..c89ebaf --- /dev/null +++ b/AI-Agent-Standards/templates/repo/guide/README.md @@ -0,0 +1,30 @@ +# Guides + + + +**Owner:** panduan operasional berurutan (setup, deploy, runbook, migrasi, troubleshooting alur). + +## Indeks Guide + +| Guide | Path | Kapan dipakai | +|-------|------|---------------| +| Migrasi server/domain | [migration.md](./migration.md) | Pindah server, ganti IP/domain, cutover env | +| | [nama.md](./nama.md) | | + +**Wajib ada:** [migration.md](./migration.md) untuk semua project (isi saat migrasi atau placeholder checklist). + +## Template Guide tambahan + +# {Judul Guide} + +## Prasyarat +- {prasyarat} + +## Langkah +1. {langkah 1} + +## Verifikasi +- {cara memastikan berhasil} + +## Rollback +- {jika gagal} \ No newline at end of file diff --git a/AI-Agent-Standards/templates/repo/guide/migration.md b/AI-Agent-Standards/templates/repo/guide/migration.md new file mode 100644 index 0000000..9952246 --- /dev/null +++ b/AI-Agent-Standards/templates/repo/guide/migration.md @@ -0,0 +1,120 @@ +# Migration Guide — Server & Domain + + + + +**Owner:** checklist migrasi server/domain, urutan cutover, verifikasi, rollback. +Inventori host: [../server.md](../server.md). Requirement tool: [../system-requirements.md](../system-requirements.md). +Template env: `../../.env.example` (root project). + +**Prinsip:** URL/domain **dynamic** — ubah `.env` / config, bukan source code (kecuali refactor env var baru). + +--- + +## Kapan pakai guide ini + +- Migrasi app/service ke server baru (IP/host berubah) +- Ganti domain (mis. `old.example.com` -> `new.example.com`) +- Pindah database ke host/instance baru +- Cutover staging -> prod dengan URL baru + +--- + +## Inventori sebelum migrasi + +| Item | Nilai saat ini | Nilai target | File yang harus diupdate | +|------|----------------|--------------|--------------------------| +| Domain / base URL | | | `.env.example`, `.env` (lokal), [server.md](../server.md) | +| API base URL | | | kode baca env saja | +| DB host | | | `.env.example`, server.md | +| Reverse proxy | | | nginx/IIS config path di repo | +| SSL / cert | | | | +| DNS record | | | catatan di server.md | + +--- + +## Variabel env yang terpengaruh + +Salin dari `.env.example`, isi kolom old/new: + +| Variabel | Old | New | Sudah di `.env` prod? | +|----------|-----|-----|------------------------| +| `API_BASE_URL` | | | | +| `APP_URL` | | | | +| `DB_HOST` | | | | +| `{CUSTOM}` | | | | + +Commit yang boleh: `.env.example`, docs — **jangan** commit `.env` berisi secret. + +--- + +## Langkah migrasi (server) + +1. **Persiapan** + - [ ] Backup data & config server lama + - [ ] Server baru memenuhi [system-requirements.md](../system-requirements.md) + - [ ] Install runtime/stack (Docker, nginx, DB, dll.) di server baru + - [ ] Siapkan `.env` di server baru dari `.env.example` + +2. **Deploy ke server baru (parallel)** + - [ ] Deploy kode/config ke server baru + - [ ] Point `.env` ke dependency internal (DB, Redis, dll.) + - [ ] Smoke test internal (IP/host langsung, belum DNS publik) + +3. **Cutover** + - [ ] Update DNS / firewall / load balancer + - [ ] Update reverse proxy (nginx/IIS) ke backend baru + - [ ] Update `.env` production dengan URL/host final + - [ ] Restart service / container + +4. **Verifikasi** + - [ ] Health check endpoint + - [ ] Login / auth flow + - [ ] Integrasi ke project monorepo lain (jika ada) + - [ ] Client app (APK/web) masih pakai env — rebuild hanya jika BuildConfig berubah + +5. **Dokumentasi (wajib)** + - [ ] Update [../server.md](../server.md) (host, URL, mapping path) + - [ ] Update `.env.example` jika nama variabel/placeholder berubah + - [ ] Append entri migrasi di [../version.md](../version.md) + [../changelog.md](../changelog.md) + - [ ] Overwrite [../ai-session-summary.md](../ai-session-summary.md) (Tier 1 handover) + +--- + +## Langkah migrasi (domain saja, server sama) + +1. [ ] Tambah DNS / cert untuk domain baru +2. [ ] Update reverse proxy `server_name` / binding +3. [ ] Ubah `.env`: `API_BASE_URL`, `APP_URL`, `CORS_ORIGIN`, dll. +4. [ ] Redirect domain lama -> baru (opsional, periode transisi) +5. [ ] Update docs: server.md, .env.example +6. [ ] Smoke test dari client dengan URL baru + +**Tidak perlu** ubah kode jika semua URL sudah dari env. + +--- + +## Android / mobile (Kotlin Agent dll.) + +| Area | Saat migrasi domain | +|------|---------------------| +| Base URL API | `gradle.properties` / `BuildConfig` / flavor — bukan hardcode di `.kt` | +| Network security | `network_security_config.xml` jika domain/cert berubah | +| Release | Rebuild APK jika BuildConfig berubah; OTA channel sesuai [release guide] | + +--- + +## Rollback + +1. Kembalikan DNS / proxy ke server/domain lama +2. Restore `.env` backup +3. Restart service +4. Catat rollback di [../issues.md](../issues.md) + session summary + +--- + +## Riwayat migrasi + +| Tanggal | Dari | Ke | Session / versi | Catatan | +|---------|------|-----|-----------------|---------| +| {YYYY-MM-DD} | {old host/domain} | {new} | {session-id} | | \ No newline at end of file diff --git a/AI-Agent-Standards/templates/repo/issues.md b/AI-Agent-Standards/templates/repo/issues.md new file mode 100644 index 0000000..c8f346d --- /dev/null +++ b/AI-Agent-Standards/templates/repo/issues.md @@ -0,0 +1,52 @@ +# Issues + + + +**Owner:** detail bug, root cause, workaround, limitation (single source). +Session summary dan project-status hanya merujuk ID issue — jangan salin RCA penuh. + +--- + +## Open Issues + +### ISS-{NNN}: {Judul} + +| Field | Value | +|-------|-------| +| Status | Open | +| Severity | Critical/High/Medium/Low | +| Found | {YYYY-MM-DD} | +| Session | {session-id} | + +**Deskripsi:** +{deskripsi singkat} + +**Root Cause:** +{root cause jika diketahui} + +**Workaround:** +{workaround jika ada} + +**Files terkait:** +- `path/to/file` + +--- + +## Resolved Issues + +### ISS-{NNN}: {Judul} + +| Field | Value | +|-------|-------| +| Status | Resolved | +| Resolved | {YYYY-MM-DD} | +| Fix | {ringkasan fix} | +| Version | {x.y.z — lihat version.md} | + +--- + +## Known Limitations + +| ID | Limitation | Reason | Ref | +|----|------------|--------|-----| +| LIM-001 | | | | \ No newline at end of file diff --git a/AI-Agent-Standards/templates/repo/project-status.md b/AI-Agent-Standards/templates/repo/project-status.md new file mode 100644 index 0000000..42106c0 --- /dev/null +++ b/AI-Agent-Standards/templates/repo/project-status.md @@ -0,0 +1,71 @@ +# Project Status + + + +> Last updated: {YYYY-MM-DD} +> Session: [ai-session-summary.md](./ai-session-summary.md) + +**Owner:** ringkasan progress area (Done / In Progress / Blocked / Planned), blocker, technical debt ringkas. +**Bukan owner:** daftar TODO (lihat todo.md), detail bug (lihat issues.md), narasi sesi (lihat session summary). + +--- + +## Ringkasan + +{1-2 kalimat status proyek saat ini} + +--- + +## Progress + +| Area | Status | Catatan | +|------|--------|---------| +| {area} | {Done/In Progress/Blocked/Planned} | | + +--- + +## Fitur Selesai + +- [x] {fitur} + +--- + +## Fitur Sedang Dikerjakan + +- [ ] {fitur} - {progress%} - {catatan} + +--- + +## Technical Debt (ringkas) + +> Item actionable: [todo.md](./todo.md#technical-debt) + +| Item | Prioritas | +|------|-----------| +| | High/Medium/Low | + +--- + +## Known Issues (indeks) + +> Detail: [issues.md](./issues.md) + +| ID | Issue | Status | +|----|-------|--------| +| | | Open/Resolved | + +--- + +## Blocker + +| Blocker | Impact | Action | +|---------|--------|--------| +| | | | + +--- + +## Next Priority + +> Sumber kebenaran: [todo.md](./todo.md) (High Priority) + +1. {mirror 1-3 item teratas dari todo - atau cukup link} \ No newline at end of file diff --git a/AI-Agent-Standards/templates/repo/server.md b/AI-Agent-Standards/templates/repo/server.md new file mode 100644 index 0000000..207b08d --- /dev/null +++ b/AI-Agent-Standards/templates/repo/server.md @@ -0,0 +1,93 @@ +# Server Inventory + + + + + +**Owner:** host/IP, role, aplikasi runtime, database, port, env yang dipakai **project ini**. +Indeks lintas project: monorepo root `Workspace-Context.md` (dan `SSH-HOSTS.md` jika ada) — link ke file ini, jangan duplikasi detail penuh. + +Cold start: cukup tahu path file ini dari [AGENTS.md](../AGENTS.md) / [context-index.md](./context-index.md). + +--- + +## Ringkasan + +| Field | Value | +|-------|-------| +| Project | `{path/relatif monorepo}` | +| Last updated | {YYYY-MM-DD} | +| Credential location | {vault / .env lokal — lihat .env.example} — **bukan** secret di sini | + +--- + +## Host / Server + +| Host / IP | Env | Role | OS | Akses | Catatan | +|-----------|-----|------|-----|-------|---------| +| {10.x.x.x atau hostname} | dev/staging/prod | {app / db / reverse-proxy / worker} | {Linux/Windows} | {SSH user@host / RDP} | | + +> Satu baris per host yang **benar-benar dipakai** project ini. + +--- + +## Aplikasi & Runtime per Host + +| Host / IP | Aplikasi | Jenis | Port | Path / Container | Catatan | +|-----------|----------|-------|------|------------------|---------| +| {ip} | {nama service} | Docker / nginx / IIS / Apache / systemd / Windows Service / other | {port} | {compose service / site name / unit} | | +| {ip} | {nama} | SQL Server / PostgreSQL / MySQL / Redis / other | {port} | {instance / db name} | | + +Jenis yang sering dipakai (isi yang relevan saja): +- **Web / proxy:** nginx, IIS, Apache, Caddy, Traefik +- **Runtime:** Docker, Docker Compose, Kubernetes, systemd, Windows Service +- **App:** FastAPI, Node, .NET, PHP, Java, dll. +- **Data:** SQL Server, PostgreSQL, MySQL, MariaDB, Redis, MongoDB +- **Lain:** MQTT, RabbitMQ, MinIO, dll. + +--- + +## Database + +| Host / IP | Engine | Instance / Port | Database | Dipakai untuk | Credential location | +|-----------|--------|-----------------|----------|---------------|---------------------| +| | SQL Server / PostgreSQL / ... | | | | {env var / vault} | + +--- + +## Endpoint & URL + +> Nilai runtime: variabel di .env.example (root project). **Jangan hardcode** di kode. +> Migrasi domain: [guide/migration.md](./guide/migration.md) + +| Env | URL / Host:Port | Env var | Catatan | +|-----|-----------------|--------------|---------| +| dev | | API_BASE_URL / APP_URL | | +| staging | | | | +| prod | | | | + +--- + +## Mapping ke path project (monorepo) + +| Komponen di server | Path di monorepo | Keterangan | +|--------------------|------------------|------------| +| {service / container / site} | `{path/relatif}/` | Kode / config utama | +| {nginx config / compose} | `{path}/...` | Jika config ikut di repo | + +--- + +## Dependency server ke project lain + +| Host / Service | Project monorepo | Relasi | +|----------------|------------------|--------| +| | `{path/}` | API / DB / shared network | + +--- + +## Catatan operasional + +- {firewall, VPN, ZeroTier, port expose, backup, dll. — tanpa secret} + +**Jangan:** password, API key, private key, connection string lengkap ber-credential. +**Ganti dengan:** lokasi credential + nama variabel env. \ No newline at end of file diff --git a/AI-Agent-Standards/templates/repo/system-requirements.md b/AI-Agent-Standards/templates/repo/system-requirements.md new file mode 100644 index 0000000..26525a4 --- /dev/null +++ b/AI-Agent-Standards/templates/repo/system-requirements.md @@ -0,0 +1,105 @@ +# System Requirements + + + + +**Owner:** versi minimum OS, runtime, tool chain, dependency infra yang **wajib** agar project jalan. +Bukan duplikasi `server.md` (host/IP) — fokus **apa yang harus terpasang**, bukan di server mana. + +Credential & URL: lihat `.env.example` (root project) + [server.md](./server.md). + +--- + +## Ringkasan + +| Field | Value | +|-------|-------| +| Project | `{path/relatif monorepo}` | +| Tipe | app / api / library / infra / android | +| Last updated | {YYYY-MM-DD} | + +--- + +## Platform & OS + +| Komponen | Minimum | Direkomendasikan | Catatan | +|----------|---------|------------------|---------| +| OS dev | {Windows 11 / Ubuntu 22.04 / macOS 14} | | | +| OS server | {Linux / Windows Server} | | lihat server.md | +| Arsitektur | {x64 / arm64} | | | + +--- + +## Runtime & Toolchain + +| Tool | Versi minimum | Versi dipakai saat ini | Install / cek | +|------|---------------|------------------------|---------------| +| {Node.js / Python / JDK / .NET / Go} | | | `{command --version}` | +| {Package manager} | | | | +| {Docker / Docker Compose} | | | | +| {Android Studio / Gradle / AGP} | | | khusus Android | +| {SQL client / ODBC} | | | | + +--- + +## Dependency eksternal (wajib tersedia) + +| Dependency | Versi | Dipakai untuk | Owner docs | +|------------|-------|---------------|------------| +| {PostgreSQL / SQL Server / Redis} | | | [server.md](./server.md) | +| {nginx / IIS / Apache} | | reverse proxy | [server.md](./server.md) | +| {LDAP / Authelia / MQTT} | | | | + +--- + +## Resource minimum (server / container) + +| Lingkungan | CPU | RAM | Disk | Catatan | +|------------|-----|-----|------|---------| +| dev | | | | | +| staging | | | | | +| prod | | | | | + +--- + +## Variabel URL & konfigurasi (no hardcode) + +> Semua base URL / host / domain **harus** dari env atau config — lihat `.env.example` di root project. + +| Variabel | Wajib | Contoh (bukan production) | Dipakai oleh | +|----------|-------|---------------------------|--------------| +| `API_BASE_URL` | ya | `https://api-dev.example.com` | app client | +| `{VAR_LAIN}` | | | | + +**Aturan implementasi:** +- Jangan hardcode URL/domain/IP di source code, config commit, atau docs operasional (kecuali `.env.example` placeholder). +- Android: `BuildConfig`, `gradle.properties`, network security config — bukan string literal di `.kt`. +- Backend: baca dari environment / `.env` (lokal, gitignore). + +--- + +## Port & protokol + +| Service | Port | Protokol | Catatan | +|---------|------|----------|---------| +| | | HTTP/HTTPS/TCP | | + +--- + +## Checklist setup baru (developer / server) + +- [ ] Penuhi runtime minimum di tabel di atas +- [ ] Copy `.env.example` -> `.env` (lokal, jangan commit `.env`) +- [ ] Isi URL sesuai env (dev/staging/prod) +- [ ] Verifikasi koneksi ke dependency di [server.md](./server.md) +- [ ] Smoke test sesuai [guide/migration.md](./guide/migration.md) jika migrasi + +--- + +## Perubahan requirement + +Setiap upgrade tool major, OS baru, atau dependency baru: +1. Update file ini +2. Update [version.md](./version.md) + [changelog.md](./changelog.md) +3. Update `.env.example` jika variabel URL berubah +4. Migrasi server/domain: ikuti [guide/migration.md](./guide/migration.md) \ No newline at end of file diff --git a/AI-Agent-Standards/templates/repo/todo.md b/AI-Agent-Standards/templates/repo/todo.md new file mode 100644 index 0000000..96ed799 --- /dev/null +++ b/AI-Agent-Standards/templates/repo/todo.md @@ -0,0 +1,42 @@ +# TODO + + + +> Last updated: {YYYY-MM-DD} +> Sesi terakhir: [ai-session-summary.md](./ai-session-summary.md) + +**Owner:** daftar pekerjaan aktif (High / Medium / Low) dan technical debt actionable. +Dokumen lain hanya merujuk ke sini — jangan menduplikasi daftar priority. + +--- + +## High Priority + +- [ ] {task} - {catatan singkat} + +--- + +## Medium Priority + +- [ ] {task} + +--- + +## Low Priority + +- [ ] {task} + +--- + +## Technical Debt + +- [ ] {debt item} - {prioritas} + +--- + +## Selesai (Sesi Ini) + + + +- [x] {task} - selesai {YYYY-MM-DD} \ No newline at end of file diff --git a/AI-Agent-Standards/templates/repo/version.md b/AI-Agent-Standards/templates/repo/version.md new file mode 100644 index 0000000..15adfa8 --- /dev/null +++ b/AI-Agent-Standards/templates/repo/version.md @@ -0,0 +1,29 @@ +# Version History + + + +**Owner:** riwayat versi repo dalam bentuk poin-poin per rilis/perubahan. +Setiap perbaikan atau perubahan kode/config yang material **wajib** menambah entri di sini. + +**Wajib update sebelum deploy** (install ke device, push server, rilis APK/binary, cutover prod): +1. Naikkan versi di source of truth build (`build.gradle.kts`, `package.json`, `pyproject.toml`, dll.) +2. **Append** entri baru di file ini — bullet poin jelas (apa diubah, mengapa, QC jika ada) +3. Jangan overwrite entri lama (strategi **APPEND**) + +Gunakan semver jika memungkinkan (`MAJOR.MINOR.PATCH`), atau tanggal+urutan (`YYYY.MM.DD.N`) jika belum ada skema versi. + +Sinkron dengan [changelog.md](./changelog.md): changelog = kategori Keep a Changelog; file ini = ringkasan berpoin per versi. + +--- + +## [x.y.z] - {YYYY-MM-DD} + +- {perubahan 1} +- {perubahan 2} +- {perubahan 3} + +--- + +## [0.1.0] - {YYYY-MM-DD} + +- Inisialisasi dokumentasi standar repo \ No newline at end of file diff --git a/AI-Agent-Standards/templates/workspace/Workspace-Context.md b/AI-Agent-Standards/templates/workspace/Workspace-Context.md new file mode 100644 index 0000000..bff82b5 --- /dev/null +++ b/AI-Agent-Standards/templates/workspace/Workspace-Context.md @@ -0,0 +1,156 @@ +# Workspace Context + + + +> Workspace ini adalah **monorepo** (satu git root, banyak subproject). +> "Repository" = **subproject** (folder project), bukan git repo terpisah. +> Sesi hari ini: [Workspace-Session.md](./Workspace-Session.md) +> Standar: `AI-Agent-Standards/` + +--- + +## Overview + +| Field | Value | +|-------|-------| +| Workspace | {NAMA_WORKSPACE} | +| Tipe | Monorepo | +| Root Git | `{path-root}` | +| Remote | `{url}` | +| Owner | {nama/team} | +| Last updated | {YYYY-MM-DD} | + +--- + +## Urutan baca AI (hemat token) + +``` +1. Workspace-Session.md <- Active focus dulu +2. {project}/AGENTS.md <- cold start (~200-400 token) +3. {project}/docs/ai-session-summary.md <- TL;DR + Lanjut + Jangan +4. STOP - mulai kerja +5. On-demand: todo, issues, api, guide, server.md, context-index, adr +``` + +**Target cold start: < 2000 token.** + +**Jangan baca di cold start:** changelog penuh, version history, WORKLOG, development-log, seluruh context-index. + +**Rolling session memory per project = hanya** `docs/ai-session-summary.md`. + +--- + +## Read budget + +| Tujuan | Baca maksimal | +|--------|----------------| +| Lanjut task yang sama | AGENTS + ai-session-summary | +| Ambil task baru | + todo.md (High) | +| Debug | + issues.md (ID terkait) | +| Ubah API | + docs/api/ | +| Ikuti prosedur / flow | + docs/guide/ | +| Deploy / debug koneksi / infra | + docs/server.md | +| Arsitektur | + docs/adr/ | +| Navigasi domain | + context-index.md (Zona B) | + +--- + +## Project Index + +| Project | Path | Deskripsi | Cold start | Context | +|---------|------|-----------|------------|---------| +| {name} | `{path/}` | | [`AGENTS.md`]({path}/AGENTS.md) | [`docs/context-index.md`]({path}/docs/context-index.md) | + +### Shared resources (bukan project) + +| Folder | Fungsi | +|--------|--------| +| | | + +--- + +## Dependency antar project + +| From | To | Tipe | Catatan | +|------|-----|------|---------| +| | | | | + +--- + +## Single owner (anti-duplikasi) + +| Informasi | Owner | +|-----------|-------| +| Cold start / aturan kritis | `{project}/AGENTS.md` | +| Narasi sesi (rolling) | `{project}/docs/ai-session-summary.md` | +| Priority / TODO | `{project}/docs/todo.md` | +| Bug / RCA | `{project}/docs/issues.md` | +| Changelog | `{project}/docs/changelog.md` | +| Poin versi | `{project}/docs/version.md` | +| API | `{project}/docs/api/` | +| Flow / step-by-step | `{project}/docs/guide/` | +| Server / IP / runtime / DB | `{project}/docs/server.md` | +| System requirements | `{project}/docs/system-requirements.md` | +| URL/env template | `{project}/.env.example` | +| Migrasi server/domain | `{project}/docs/guide/migration.md` | +| Peta domain (on-demand) | `{project}/docs/context-index.md` | +| Lintas project sesi | `Workspace-Session.md` | +| Peta monorepo stabil | `Workspace-Context.md` | + +Arsip (bukan jalur wajib): WORKLOG, development-log. + +--- + +## Tier handover + +### Tier 1 - Minimal + +1. OVERWRITE `docs/ai-session-summary.md` (max 80 baris; TL;DR + Lanjut + Jangan) +2. UPDATE `docs/todo.md` +3. APPEND `docs/changelog.md` + `docs/version.md` +4. UPDATE `AGENTS.md` hanya jika aturan kritis berubah + +### Tier 2 - Jika relevan + +issues, adr, guide, server.md, system-requirements.md, .env.example, guide/migration.md, project-status, context-index, api/ + +### Tier 3 - Monorepo + +OVERWRITE `Workspace-Session.md` (wajib **Active focus**) + +--- + +## Environment global + +| Env | Catatan | +|-----|---------| +| dev | | + +Credential: {vault/path} - jangan simpan secret. + +--- + +## Server Index (lintas project) + +> Indeks saja. Detail per project: `{project}/docs/server.md`. +> Inventori host bersama juga boleh di `SSH-HOSTS.md` — tetap link ke server.md project terkait. + +| Host / IP | Project monorepo | Role | Runtime ringkas | Detail | +|-----------|------------------|------|-----------------|--------| +| {10.x.x.x} | `{path}` | app/db/proxy | Docker, nginx, SQL Server, ... | [server.md]({path}/docs/server.md) | + +Satu host boleh muncul di beberapa project jika di-share; detail role per project tetap di `docs/server.md` masing-masing. + +--- + +## Standar dan perintah + +Standar: `AI-Agent-Standards/` + +| Perintah | Aksi | +|----------|------| +| `/handover` | Full tiered preservation | +| `/session-summary` | Overwrite ai-session-summary.md | +| `/workspace-summary` | Overwrite Workspace-Session.md | + +Pengetahuan penting, arsitektur, flow, **dan inventori server (IP + runtime)** yang disepakati **tidak boleh** hanya di chat AI. \ No newline at end of file diff --git a/AI-Agent-Standards/templates/workspace/Workspace-Session.md b/AI-Agent-Standards/templates/workspace/Workspace-Session.md new file mode 100644 index 0000000..cfb9691 --- /dev/null +++ b/AI-Agent-Standards/templates/workspace/Workspace-Session.md @@ -0,0 +1,71 @@ +# Workspace Session + + + + + +--- + +## Active focus + + + +- `{path}`: {status singkat} -> next: {prioritas langsung} +- `{path}`: {status singkat} -> next: {prioritas langsung} + +--- + +## Session Information + +| Field | Value | +|-------|-------| +| Tanggal | {YYYY-MM-DD} | +| Session ID | {YYYY-MM-DD-judul} | +| AI Agent | {Cursor/Cline/dll} | +| Developer | {nama jika ada} | + +--- + +## Executive Summary + +- {max 5 bullet lintas project} + +--- + +## Project yang dikerjakan + +| Project | Path | Summary | Branch | Version | +|---------|------|---------|--------|---------| +| | `{path/}` | | | {x.y.z} | + +--- + +## Cross-Project Impact + +| Perubahan | Project | Dampak ke Project Lain | +|-----------|---------|------------------------| +| | | | + +--- + +## Referensi detail (on-demand) + +| Project | Cold start | Session | Version | +|---------|------------|---------|---------| +| | [`AGENTS.md`]({path}/AGENTS.md) | [`ai-session-summary.md`]({path}/docs/ai-session-summary.md) | [`version.md`]({path}/docs/version.md) | + +--- + +## Next Priority (workspace) + +> Detail: masing-masing `docs/todo.md` + +1. {priority lintas-project} + +--- + +## Catatan lintas-project + +- {max 5 bullet} + +**Konteks stabil:** [Workspace-Context.md](./Workspace-Context.md) \ No newline at end of file diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md index 35c5f9c..95bab7e 100644 --- a/ARCHITECTURE.md +++ b/ARCHITECTURE.md @@ -169,7 +169,7 @@ sequenceDiagram FE->>Console: POST /api/v1/feedback\n{type, title, message, context} Console->>Console: Simpan ke tabel feedback Console-->>FE: {id, status: open} - Console-)Zammad: POST /api/v1/tickets ⏳\nauto-create tiket + Console-)Zammad: POST /api/v1/tickets ✅\nauto-create tiket (geonet-console `ZammadTicketService`) FE-->>User: Tampilkan nomor tiket + pesan sukses ``` diff --git a/ArcGIS Enterprise/.env.example b/ArcGIS Enterprise/.env.example new file mode 100644 index 0000000..62f6168 --- /dev/null +++ b/ArcGIS Enterprise/.env.example @@ -0,0 +1,33 @@ +# ArcGIS Enterprise — .env.example (template, aman di-commit) +# Salin ke .env lalu isi username & password + +# ============================================================================= +# SQL Server — main-db 10.100.1.25 +# ============================================================================= +MSSQL_HOST=10.100.1.25 +MSSQL_PORT=1433 +MSSQL_DATABASE=master +MSSQL_USERNAME=sa +MSSQL_PASSWORD=change-me +MSSQL_ENCRYPT=false +MSSQL_TRUST_SERVER_CERTIFICATE=true + +# ============================================================================= +# PostgreSQL — main-db 10.100.1.25 +# ============================================================================= +POSTGRES_HOST=10.100.1.25 +POSTGRES_PORT=5432 +POSTGRES_DATABASE=geonetagent_dev +POSTGRES_USERNAME=geonet_collector +POSTGRES_PASSWORD=change-me + +# DATABASE_URL=postgresql://geonet_collector:change-me@10.100.1.25:5432/geonetagent_dev + +# ============================================================================= +# ArcGIS topology +# ============================================================================= +ARCGIS_BASE_HOST=10.100.1.51 +ARCGIS_PORTAL_URL=https://dev.gisportal.id/portal +ARCGIS_SERVER_HOST=10.100.1.51 +ARCGIS_DS_OBJECT_HOST=10.100.1.52 +ARCGIS_DS_SPATIO_HOST=10.100.1.53 diff --git a/ArcGIS Enterprise/AGENTS.md b/ArcGIS Enterprise/AGENTS.md new file mode 100644 index 0000000..fefe38f --- /dev/null +++ b/ArcGIS Enterprise/AGENTS.md @@ -0,0 +1,32 @@ +# AGENTS.md — Cold Start + +> Project: ArcGIS Enterprise/ +> Sesi: [docs/ai-session-summary.md](./docs/ai-session-summary.md) +> Peta: [docs/context-index.md](./docs/context-index.md) + +## Apa ini? + +ESRI ArcGIS Enterprise dev — Portal, Server, Web Adaptor, Data Stores + +## Aturan kritis + +- dev.gisportal.id DNS langsung ke .51 — bypass reverse proxy +- No commit license / credential ESRI +- Perubahan topology → append docs/version.md + ADR +- **No hardcoded URL** — .env.example + +- No commit kecuali user minta +- Pengetahuan penting wajib ke docs + +## Lanjut kerja + +1. AGENTS.md → docs/ai-session-summary.md → STOP +2. docs/server.md, docs/todo.md + +## Pointer + +| Butuh | Buka | +|-------|------| +| Versi | [docs/version.md](./docs/version.md) | +| Server | [docs/server.md](./docs/server.md) | +| Migrasi | [docs/guide/migration.md](./docs/guide/migration.md) | diff --git a/ArcGIS Enterprise/ArcGIS Base Development/ArcGIS Server.md b/ArcGIS Enterprise/ArcGIS Base Development/ArcGIS Server.md new file mode 100644 index 0000000..e81aa27 --- /dev/null +++ b/ArcGIS Enterprise/ArcGIS Base Development/ArcGIS Server.md @@ -0,0 +1,303 @@ +# ArcGIS Server — DEV11 (ArcGIS Base Development) + +**Terakhir diaudit:** 6 Jul 2026 12:36 WIB +**Host:** `10.100.1.51` (DEV11) · **Versi:** ArcGIS Server 12.0.58905 +**URL publik:** `https://dev.gisportal.id/server` + +## Akses + +```text +ssh dev51-base +ArcGIS Server Manager : https://dev.gisportal.id/server/admin +REST Services Directory: https://dev.gisportal.id/server/rest/services +``` + +--- + +## Status Saat Audit (6 Jul 2026) + +| Item | Status | +|------|--------| +| Windows Service `ArcGIS Server` | ✅ Running (Auto) | +| ArcGIS Server internal port `6099` | ✅ Listening | +| Web Adaptor HTTPS internal `6443` | ✅ Listening (javaw) | +| IIS App Pool `ArcGISWebAdaptorAppPoolserver` | ✅ Started | +| REST publik (Herewego sample) | ✅ HTTP 200 | +| Uptime server | ⚠️ **Baru reboot** 06 Jul 2026 11:09 WIB (~1,5 jam sebelum audit) | + +> Server baru saja di-restart pagi ini. Pola ini **sesuai laporan issue**: service normal setelah reboot Windows, lalu error setelah beberapa jam. + +--- + +## Service Contoh — Herewego/Tour_Planning_Sample + +| Endpoint | Status audit | Layer | +|----------|-------------|-------| +| [MapServer](https://dev.gisportal.id/server/rest/services/Herewego/Tour_Planning_Sample/MapServer) | ✅ OK | Tour Planning Sample, Depots, Orders, Vehicle | +| [FeatureServer](https://dev.gisportal.id/server/rest/services/Herewego/Tour_Planning_Sample/FeatureServer) | ✅ OK | Depots, Orders, Vehicle + table Sample Vehicle Type | + +- Spatial Reference: **EPSG 4326** +- Extent: area Bogor/Jakarta (~106.77–106.86, -6.32 – -6.16) +- Keywords: Here, Here Simulation, Demo, Tour Planning + +--- + +## Published Services (Ringkasan) + +| Lokasi | Jumlah | +|--------|--------| +| Root (`/rest/services`) | 8 | +| Folder user (21 folder) | 66 | +| **Total user services** | **~74** | +| System + Utilities | +30 (internal ArcGIS) | + +### Folder user + +| Folder | Services | +|--------|----------| +| Hosted | 20 | +| Umar | 9 | +| agriculture | 6 | +| mfajri | 6 | +| test_fayra | 4 | +| Training_Experience_Builder | 4 | +| GeonetLocation, Herewego | 2 masing-masing | +| 3D_Drone, electricity, HGDS, Onemap_Cibinong, pajakreklame, researchpublish, RnD, RnD_Gov_Disaster, telekomunikasi, Test, testdiky3, Vidya, water | 1 masing-masing | + +### Root services + +- `3D_Merapi_Public_WEL` [ImageServer] +- `3D_Merapi_WEL1` [ImageServer] +- `Batas_Kelurahan` [FeatureServer, MapServer] +- `CC_Point_CCTV1` [FeatureServer, MapServer] +- `test_feature_MIL1` [MapServer] +- `Water_MIL1` [MapServer] + +--- + +## Proses & Resource + +| Metrik | Nilai | +|--------|-------| +| ArcSOC processes | **76** | +| Total proses ArcGIS (ArcSOC + Server + Java + postgres DS) | **158** | +| Working Set total | **~24 GB** | +| Private Memory total | **~33 GB** | +| RAM server | 128 GB (18,7% terpakai saat audit) | +| Disk C: free | 320 GB (37% terpakai) | + +### Java / Portal (co-located) + +| Proses | WS | PM | +|--------|----|----| +| java (Portal) | 2,4 GB | 2,4 GB | +| javaw (Server/Portal) | 0,8 + 1,1 + 0,3 GB | ~7,4 GB | + +### ArcSOC memory (top) + +- ~250–330 MB WS per instance +- Banyak instance start 11:11 dan 12:00 WIB (setelah reboot) + +--- + +## Arsitektur Akses + +```text +Internet / LAN + │ + ▼ +https://dev.gisportal.id/server (NAT → 10.100.1.51:443) + │ + ▼ +IIS Web Adaptor (/server → ArcGISWebAdaptorAppPoolserver) + │ + ▼ +https://dev11.gisportal.id:6443 (internal Server HTTPS) + │ + ▼ +ArcGIS Server (port 6099, service ArcGISServer.exe) + │ + ▼ +ArcSOC instances (satu atau lebih per published service) +``` + +**Web Adaptor config:** `C:\inetpub\wwwroot\server\WebAdaptor.config` +- Server URL internal: `https://dev11.gisportal.id:6443` +- HTTP port internal: `6080` + +--- + +## Windows Services ArcGIS + +| Service | Status | StartType | +|---------|--------|-----------| +| ArcGIS Server | Running | Automatic | +| Portal for ArcGIS | Running | Automatic | +| ArcGIS Data Store | Running | Automatic | +| ArcGIS Monitor Agent | Running | Automatic | + +--- + +## Port Listening (ArcGIS) + +| Port | Proses | Fungsi | +|------|--------|--------| +| 443 | IIS (System) | Web Adaptor HTTPS publik | +| 6080 | javaw | Server HTTP internal | +| 6099 | ArcGISServer | Server admin/REST internal | +| 6443 | javaw | Server HTTPS internal (Web Adaptor target) | + +--- + +## IIS App Pool — Server Web Adaptor + +| Setting | Nilai | Catatan | +|---------|-------|---------| +| Name | `ArcGISWebAdaptorAppPoolserver` | | +| State | Started | | +| Idle timeout | `00:00:00` | Disabled (bagus) | +| Periodic restart | **1.05:00:00** (~29 jam) | ⚠️ Bisa putus koneksi sementara | +| Private memory limit | 0 (unlimited) | | + +--- + +## Temuan Event Log (7 hari terakhir) + +### DCOM Error 10016 — ⚠️ Berulang hari ini + +``` +The application-specific permission settings do not grant Local Activation permission +for COM Server CLSID {D63B10C5-BB46-4990-A94F-E40B9D520160} +to user IIS APPPOOL\ArcGISWebAdaptorAppPoolserver +``` + +- Terjadi berkali-kali sejak reboot (11:10–11:47 WIB) +- Juga muncul untuk user `DEV11\arcgis` +- **Kemungkinan penyebab intermiten:** Web Adaptor IIS gagal komunikasi COM ke ArcGIS Server component + +### Application Error (ArcGIS/ArcSOC) + +- Tidak ada entry error ArcGIS di Application log 7 hari terakhir (saat audit) + +--- + +## Log Server + +**Path:** `C:\Program Files\ArcGIS\Server\usr\logs\DEV11.GISPORTAL.ID\` + +| Lokasi | Isi | +|--------|-----| +| `services\\` | Log per published service (ArcSOC) | +| `server\` | Log komponen server | + +Log terakhir yang terlihat: Jan 2026 (ImageServer 3D_Merapi) — sedikit log baru hari ini, kemungkinan karena baru reboot. + +--- + +## Analisis Issue: Service Tidak Dapat Diakses Setelah Beberapa Jam + +### Pola yang cocok dengan gejala + +1. **Server baru reboot → semua OK** (terverifikasi audit ini) +2. **76 ArcSOC untuk ~74 service** — instance menumpuk seiring waktu +3. **ArcSOC crash / hang** — proses mati tapi service masih "Started" di Manager +4. **Web Adaptor ↔ Server putus** — DCOM error, port 6443 tidak merespons +5. **IIS App Pool recycle** — setiap ~29 jam, bisa ganggu koneksi aktif +6. **Semua komponen Enterprise di 1 mesin** — Portal + Server + Data Store + Laragon + 74 service = beban tinggi + +### Kemungkinan penyebab (prioritas) + +| # | Penyebab | Indikator | +|---|----------|-----------| +| 1 | **ArcSOC instance mati/hang** | Service error di REST tapi Windows Service masih Running | +| 2 | **DCOM permission Web Adaptor** | Event 10016 berulang di System log | +| 3 | **Memory leak ArcSOC** | RAM naik gradual; saat ini 24 GB dari 158 proses | +| 4 | **Terlalu banyak published service aktif** | 74 user service + System = 76+ ArcSOC | +| 5 | **Internal HTTPS 6443 gagal** | Web Adaptor tidak reach Server meski 6099 hidup | +| 6 | **Co-located Portal + DS** | Kontention CPU/RAM/I/O setelah uptime panjang | + +### Yang BUKAN penyebab (saat audit) + +- RAM penuh — masih 104 GB free +- Disk penuh — masih 320 GB free +- Windows Service stopped — semua Running +- Firewall block — REST publik OK dari luar + +--- + +## Langkah Diagnostik Saat Issue Terjadi + +Jalankan via SSH ke DEV11: + +```powershell +# 1. Cek Windows Service +Get-Service 'ArcGIS Server','Portal for ArcGIS','ArcGIS Data Store' + +# 2. Cek port internal +Test-NetConnection localhost -Port 6099 +Test-NetConnection localhost -Port 6443 + +# 3. Hitung ArcSOC +(Get-Process ArcSOC -ErrorAction SilentlyContinue).Count + +# 4. Test REST publik vs internal +Invoke-WebRequest 'https://dev.gisportal.id/server/rest/services?f=pjson' -UseBasicParsing +# Internal (dari server, pakai hostname bukan localhost): +Invoke-WebRequest 'https://dev11.gisportal.id/server/rest/services?f=pjson' -UseBasicParsing + +# 5. Cek log service spesifik +Get-ChildItem 'C:\Program Files\ArcGIS\Server\usr\logs\DEV11.GISPORTAL.ID\services' -Recurse -Filter '*.log' | + Sort-Object LastWriteTime -Descending | Select-Object -First 5 + +# 6. Event log DCOM +Get-WinEvent -FilterHashtable @{LogName='System'; Id=10016; StartTime=(Get-Date).AddHours(-24)} -MaxEvents 10 +``` + +### Restart bertingkat (urutan disarankan) + +1. **Restart service di ArcGIS Server Manager** (service yang error saja) +2. **Restart Windows Service `ArcGIS Server`** (lebih cepat dari reboot penuh) +3. **Recycle IIS App Pool** `ArcGISWebAdaptorAppPoolserver` +4. **Reboot Windows** (last resort — sudah terbukti fix sementara) + +```powershell +Restart-Service 'ArcGIS Server' +Import-Module WebAdministration +Restart-WebAppPool 'ArcGISWebAdaptorAppPoolserver' +``` + +--- + +## Rekomendasi Perbaikan + +### Segera + +- [ ] **Monitor REST endpoint** via Zabbix (agent sudah terpasang port 10050): + - `https://dev.gisportal.id/server/rest/services/Herewego/Tour_Planning_Sample/MapServer?f=pjson` + - `https://dev.gisportal.id/server/rest/services?f=pjson` +- [ ] **Fix DCOM permission** untuk `IIS APPPOOL\ArcGISWebAdaptorAppPoolserver` (Component Services → DCOM Config) +- [ ] **Stop service tidak terpakai** — kurangi beban ArcSOC (74 service di dev server terlalu banyak) + +### Jangka menengah + +- [ ] **Kurangi min/max instances** per service di Server Manager (khususnya MapServer/ImageServer berat) +- [ ] **Scheduled restart** ArcGIS Server service (mis. mingguan malam hari) sebagai workaround +- [ ] **Pisahkan Portal dan Server** ke VM berbeda (best practice Enterprise) +- [ ] **Aktifkan ArcGIS Monitor** alerts (agent sudah running) untuk service down +- [ ] **Review App Pool recycle** — pertimbangkan disable periodic restart atau set waktu maintenance + +### Saat issue terjadi lagi + +- [ ] Catat uptime (`systeminfo | find "Boot Time"`) dan jumlah ArcSOC +- [ ] Simpan log dari folder service yang error sebelum restart +- [ ] Bandingkan apakah port 6443 masih listening + +--- + +## Referensi + +- Server audit host: `server-audit.md` +- SSH & topology: `server-audit/host.md`, `docs/server.md` +- Web Adaptor IIS path: `/server` → `C:\inetpub\wwwroot\server` +- Server binaries: `C:\Program Files\ArcGIS\Server\` +- Service configs on disk: `C:\arcgisserver\directories\arcgissystem\arcgisinput\` diff --git a/ArcGIS Enterprise/ArcGIS Base Development/server-audit.md b/ArcGIS Enterprise/ArcGIS Base Development/server-audit.md new file mode 100644 index 0000000..3a4cecf --- /dev/null +++ b/ArcGIS Enterprise/ArcGIS Base Development/server-audit.md @@ -0,0 +1,109 @@ +# ArcGIS Enterprise — ArcGIS Base Development + +**Terakhir diaudit:** 6 Jul 2026 + +## Akses SSH + +```text +ssh dev51-base +ssh Administrator@10.100.1.51 -p 22 +``` + +- Key: `~/.ssh/id_ed25519_geonet_proxmox` +- Login key-only (passwordless) via `C:\ProgramData\ssh\administrators_authorized_keys` + +## Identitas Server + +| Item | Nilai | +|------|-------| +| Hostname | DEV11 | +| IP | 10.100.1.51 | +| OS | Windows Server 2016 Standard (build 10.0.14393) | +| RAM | 128 GB | +| Disk C: | 511 GB — terpakai ~37% (320 GB free) | +| Hypervisor | Proxmox (Virtio-win drivers terpasang) | + +## Stack ArcGIS Enterprise (utama) + +| Komponen | Versi | Status | +|----------|-------|--------| +| Portal for ArcGIS | 12.0.58905 | Running | +| ArcGIS Server | 12.0.58905 | Running | +| ArcGIS Data Store (Relational) | 12.0.58905 | Running | +| ArcGIS Web Adaptor (IIS) | 11.4 & 12.0 | Terpasang | +| ArcGIS Pro | 3.5.57366 | Terpasang | +| ArcGIS Insights | 2023.3.0.5972 | Terpasang | +| ArcGIS Monitor | 2023.3.1 | Running (agent) | + +**Direktori ArcGIS:** `C:\Program Files\ArcGIS\{Portal,Server,DataStore,Monitor}` + +### IIS — Web Adaptor (Default Web Site, port 80/443) + +| Path | App Pool | +|------|----------| +| `/portal` | ArcGISWebAdaptorAppPoolportal | +| `/server` | ArcGISWebAdaptorAppPoolserver | +| `/image` | ArcGISWebAdaptorAppPoolimage | +| `/notebook` | ArcGISWebAdaptorAppPoolnotebook | +| `/notebooksvr` | ArcGISWebAdaptorAppPoolnotebooksvr | +| `/workflow` | ArcGISWebAdaptorAppPoolworkflow | +| `/knowledge` | ArcGISWebAdaptorAppPoolknowledge | +| `/geoevent` | ArcGISWebAdaptorAppPoolgeoevent | +| `/exbapp` | DefaultAppPool (Experience Builder) | + +### Service ArcGIS yang berjalan + +- Portal for ArcGIS +- ArcGIS Server +- ArcGIS Data Store +- ArcGIS Monitor Agent + +## Aplikasi Non-Bawaan Windows (lainnya) + +### Development + +| Aplikasi | Versi | Catatan | +|----------|-------|---------| +| Laragon | 5.0.0 | `C:\laragon` — PHP 7.4, MySQL 5.7, Apache 2.4, Node 14, Redis, Memcached | +| DBeaver | 7.3.3 | DB client | +| SQL Server Management Studio | 18.5.1 | | +| Integration Services (SSIS) | 15.0 | | +| .NET SDK | 8.0.302 | + ASP.NET Core Hosting Bundle 6.0 & 8.0 | +| ODBC Driver 17 / OLE DB Driver | 17.5 / 18.3 | SQL Server connectivity | +| SQL Server 2012 Native Client | 11.4 | | + +### Utilitas & Monitoring + +| Aplikasi | Versi | +|----------|-------| +| Google Chrome | 149.0.7827.201 | +| Notepad++ | 8.4.2 | +| WinRAR | 5.70 | +| MiniTool Partition Wizard | 12.1.0 | +| Zabbix Agent | 6.2.1 (port 10050) | +| OpenSSH Server | 10.0 (port 22) | +| Microsoft Web Deploy | 4.0 | + +## Port Penting + +| Port | Proses | Fungsi | +|------|--------|--------| +| 22 | sshd | SSH | +| 80 / 443 | IIS | Web Adaptor | +| 6099 | ArcGISServer | Server internal | +| 7099 | ArcGISPortal | Portal internal | +| 9099 | ArcGISDataStore | Data Store internal | +| 7654, 9876 | postgres | PostgreSQL (Data Store) | +| 10050 | zabbix_agentd | Monitoring | + +## Fitur Windows Bawaan (relevan) + +- IIS (Web Server, ASP.NET 4.6, Windows Auth, WebSocket) +- .NET Framework 3.5 & 4.6 +- Windows Defender, PowerShell 5.1, File Server / SMB + +## Catatan + +- Server berperan sebagai **ArcGIS Enterprise Base Development** lengkap (Portal + Server + Data Store + Web Adaptor). +- Tambahan di luar docs awal: ArcGIS Pro, Insights, Monitor, dan Laragon (dev stack PHP/MySQL). +- Banyak instance **ArcSOC** aktif — normal untuk ArcGIS Server dengan banyak service/geoprocessing. diff --git a/ArcGIS Enterprise/docs/adr/000-template.md b/ArcGIS Enterprise/docs/adr/000-template.md new file mode 100644 index 0000000..e729785 --- /dev/null +++ b/ArcGIS Enterprise/docs/adr/000-template.md @@ -0,0 +1,3 @@ +# ADR template + +Salin untuk keputusan arsitektur baru. diff --git a/ArcGIS Enterprise/docs/ai-session-summary.md b/ArcGIS Enterprise/docs/ai-session-summary.md new file mode 100644 index 0000000..3aeb414 --- /dev/null +++ b/ArcGIS Enterprise/docs/ai-session-summary.md @@ -0,0 +1,14 @@ +# AI Session Summary + +`yaml +session: 2026-07-06-init +project: ArcGIS Enterprise/ +version: 0.1.0 +status: ready +next: Lengkapi operasional dari server live +` + +## TL;DR + +- Bootstrap docs AI-Agent-Standards untuk infra ArcGIS Enterprise +- Host utama: 10.100.1.51 (dev.gisportal.id) diff --git a/ArcGIS Enterprise/docs/changelog.md b/ArcGIS Enterprise/docs/changelog.md new file mode 100644 index 0000000..5d48d7b --- /dev/null +++ b/ArcGIS Enterprise/docs/changelog.md @@ -0,0 +1,6 @@ +# Changelog — ArcGIS Enterprise + +## [0.1.0] - 2026-07-06 + +### Added +- Struktur dokumentasi AI-Agent-Standards diff --git a/ArcGIS Enterprise/docs/context-index.md b/ArcGIS Enterprise/docs/context-index.md new file mode 100644 index 0000000..688f7d0 --- /dev/null +++ b/ArcGIS Enterprise/docs/context-index.md @@ -0,0 +1,20 @@ +# Context Index — ArcGIS Enterprise + +## Zona A + +| Item | Value | +|------|-------| +| Path | ArcGIS Enterprise/ | +| Cold start | [../AGENTS.md](../AGENTS.md) | +| Versi | 0.1.0 — [version.md](./version.md) | +| Stack | Windows Server, IIS, ArcGIS Enterprise | +| Tipe | infra | +| Last updated | 2026-07-06 | + +## Zona B + +| Dokumen | Path | +|---------|------| +| Server | [server.md](./server.md) | +| Todo | [todo.md](./todo.md) | +| Migrasi | [guide/migration.md](./guide/migration.md) | diff --git a/ArcGIS Enterprise/docs/guide/README.md b/ArcGIS Enterprise/docs/guide/README.md new file mode 100644 index 0000000..e724bbb --- /dev/null +++ b/ArcGIS Enterprise/docs/guide/README.md @@ -0,0 +1,3 @@ +# Guides + +- [migration.md](./migration.md) diff --git a/ArcGIS Enterprise/docs/guide/migration.md b/ArcGIS Enterprise/docs/guide/migration.md new file mode 100644 index 0000000..9c9dc87 --- /dev/null +++ b/ArcGIS Enterprise/docs/guide/migration.md @@ -0,0 +1,11 @@ +# Migration Guide + +## Topology + +| Host | Role | +|------|------| +| 10.100.1.51 | Portal, Server, DS Relational, IIS | +| 10.100.1.52 | Data Store Object | +| 10.100.1.53 | Data Store Spatio | + +DNS: dev.gisportal.id → 10.100.1.51 (tidak lewat nginx .24) diff --git a/ArcGIS Enterprise/docs/issues.md b/ArcGIS Enterprise/docs/issues.md new file mode 100644 index 0000000..8a107e9 --- /dev/null +++ b/ArcGIS Enterprise/docs/issues.md @@ -0,0 +1,3 @@ +# Issues + +Belum ada issue terdokumentasi. diff --git a/ArcGIS Enterprise/docs/project-status.md b/ArcGIS Enterprise/docs/project-status.md new file mode 100644 index 0000000..8665363 --- /dev/null +++ b/ArcGIS Enterprise/docs/project-status.md @@ -0,0 +1,8 @@ +# Project Status — ArcGIS Enterprise + +ESRI ArcGIS Enterprise dev — Portal, Server, Web Adaptor, Data Stores + +| Item | Status | +|------|--------| +| Dokumentasi bootstrap | Done 2026-07-06 | +| Operasional | Lihat server.md | diff --git a/ArcGIS Enterprise/docs/server.md b/ArcGIS Enterprise/docs/server.md new file mode 100644 index 0000000..e96986f --- /dev/null +++ b/ArcGIS Enterprise/docs/server.md @@ -0,0 +1,29 @@ +# Server — ArcGIS Enterprise + +> **Last updated:** 2026-07-06 + +## Topology + +| Host | IP | Role | +|------|-----|------| +| ArcGIS Base | `10.100.1.51` | Portal, Server, Web Adaptor, DS Relational, IIS | +| DS Object | `10.100.1.52` | Data Store Object | +| DS Spatio | `10.100.1.53` | Data Store Spatio | + +## DNS + +| Domain | Routing | +|--------|---------| +| `dev.gisportal.id` | Langsung `10.100.1.51` — **bypass** nginx `.24` | +| Publik | `117.102.73.100` → NAT `10.100.1.51:443` | + +## SSH aliases + +```bash +ssh dev51-base # 10.100.1.51 +ssh dev13-object # 10.100.1.52 (verify alias di server-audit/host.md) +``` + +Detail: `ARCHITECTURE.md`, `server-audit/host.md` § ArcGIS. + +**Aturan:** perubahan topology → ADR + version.md. diff --git a/ArcGIS Enterprise/docs/system-requirements.md b/ArcGIS Enterprise/docs/system-requirements.md new file mode 100644 index 0000000..dfc5360 --- /dev/null +++ b/ArcGIS Enterprise/docs/system-requirements.md @@ -0,0 +1,8 @@ +# System Requirements — ArcGIS Enterprise + +| Field | Value | +|-------|-------| +| Stack | Windows Server, IIS, ArcGIS Enterprise | +| Host | 10.100.1.51 | + +Env: [../.env.example](../.env.example) diff --git a/ArcGIS Enterprise/docs/todo.md b/ArcGIS Enterprise/docs/todo.md new file mode 100644 index 0000000..5550885 --- /dev/null +++ b/ArcGIS Enterprise/docs/todo.md @@ -0,0 +1,9 @@ +# TODO — ArcGIS Enterprise + +## High + +- [ ] Verifikasi config live vs dokumentasi repo + +## Selesai + +- [x] Bootstrap AI-Agent-Standards 2026-07-06 diff --git a/ArcGIS Enterprise/docs/version.md b/ArcGIS Enterprise/docs/version.md new file mode 100644 index 0000000..7dc1279 --- /dev/null +++ b/ArcGIS Enterprise/docs/version.md @@ -0,0 +1,6 @@ +# Version History + +## [0.1.0] - 2026-07-06 + +- Bootstrap dokumentasi AI-Agent-Standards +- Topology dari ARCHITECTURE.md: .51 base, .52 object DS, .53 spatio DS diff --git a/Dockge/.env.example b/Dockge/.env.example new file mode 100644 index 0000000..f51eb49 --- /dev/null +++ b/Dockge/.env.example @@ -0,0 +1,6 @@ +# Dockge — .env.example +DOCKGE_PRIMARY_URL=https://dockge.gisportal.id +DOCKGE_PRIMARY_HOST=10.100.1.24 +DOCKGE_STACKS_PATH=/opt/stacks +DOCKGE_AGENT_MAILCOW_HOST=10.100.1.28 +DOCKGE_AGENT_MAILCOW_PORT=5001 diff --git a/Dockge/AGENTS.md b/Dockge/AGENTS.md new file mode 100644 index 0000000..9b40f04 --- /dev/null +++ b/Dockge/AGENTS.md @@ -0,0 +1,33 @@ +# AGENTS.md — Cold Start + +> Project: Dockge/ +> Sesi: [docs/ai-session-summary.md](./docs/ai-session-summary.md) +> Peta: [docs/context-index.md](./docs/context-index.md) + +## Apa ini? + +Docker stack manager — dockge.gisportal.id; primary .24 + agents remote + +## Aturan kritis + +- Stack path standar: /opt/stacks/{nama} +- Agent remote: port 5001 (LAN only) +- Deploy stack → append docs/version.md +- No commit secret compose .env +- **No hardcoded URL** — .env.example + +- No commit kecuali user minta +- Pengetahuan penting wajib ke docs + +## Lanjut kerja + +1. AGENTS.md → docs/ai-session-summary.md → STOP +2. docs/server.md, docs/todo.md + +## Pointer + +| Butuh | Buka | +|-------|------| +| Versi | [docs/version.md](./docs/version.md) | +| Server | [docs/server.md](./docs/server.md) | +| Migrasi | [docs/guide/migration.md](./docs/guide/migration.md) | diff --git a/Dockge/docs/adr/000-template.md b/Dockge/docs/adr/000-template.md new file mode 100644 index 0000000..e729785 --- /dev/null +++ b/Dockge/docs/adr/000-template.md @@ -0,0 +1,3 @@ +# ADR template + +Salin untuk keputusan arsitektur baru. diff --git a/Dockge/docs/ai-session-summary.md b/Dockge/docs/ai-session-summary.md new file mode 100644 index 0000000..a0c83a8 --- /dev/null +++ b/Dockge/docs/ai-session-summary.md @@ -0,0 +1,14 @@ +# AI Session Summary + +`yaml +session: 2026-07-06-init +project: Dockge/ +version: 1.5.0 +status: ready +next: Lengkapi operasional dari server live +` + +## TL;DR + +- Bootstrap docs AI-Agent-Standards untuk infra Dockge +- Host utama: 10.100.1.24 (dockge.gisportal.id) diff --git a/Dockge/docs/changelog.md b/Dockge/docs/changelog.md new file mode 100644 index 0000000..14efe6c --- /dev/null +++ b/Dockge/docs/changelog.md @@ -0,0 +1,6 @@ +# Changelog — Dockge + +## [1.5.0] - 2026-07-06 + +### Added +- Struktur dokumentasi AI-Agent-Standards diff --git a/Dockge/docs/context-index.md b/Dockge/docs/context-index.md new file mode 100644 index 0000000..6d60ca6 --- /dev/null +++ b/Dockge/docs/context-index.md @@ -0,0 +1,20 @@ +# Context Index — Dockge + +## Zona A + +| Item | Value | +|------|-------| +| Path | Dockge/ | +| Cold start | [../AGENTS.md](../AGENTS.md) | +| Versi | 1.5.0 — [version.md](./version.md) | +| Stack | Dockge v1.5.0, /opt/stacks/ | +| Tipe | infra | +| Last updated | 2026-07-06 | + +## Zona B + +| Dokumen | Path | +|---------|------| +| Server | [server.md](./server.md) | +| Todo | [todo.md](./todo.md) | +| Migrasi | [guide/migration.md](./guide/migration.md) | diff --git a/Dockge/docs/guide/README.md b/Dockge/docs/guide/README.md new file mode 100644 index 0000000..e724bbb --- /dev/null +++ b/Dockge/docs/guide/README.md @@ -0,0 +1,3 @@ +# Guides + +- [migration.md](./migration.md) diff --git a/Dockge/docs/guide/migration.md b/Dockge/docs/guide/migration.md new file mode 100644 index 0000000..d1c28c6 --- /dev/null +++ b/Dockge/docs/guide/migration.md @@ -0,0 +1,12 @@ +# Migration Guide + +## Stacks + +Semua stack Docker production di /opt/stacks/ pada host terkait. + +| Host | Role | +|------|------| +| 10.100.1.24 | Dockge primary + mayoritas stack | +| 10.100.1.28 | Dockge agent (Mailcow) | + +Migrasi stack: export compose + volume backup → deploy di host baru → update nginx. diff --git a/Dockge/docs/issues.md b/Dockge/docs/issues.md new file mode 100644 index 0000000..8a107e9 --- /dev/null +++ b/Dockge/docs/issues.md @@ -0,0 +1,3 @@ +# Issues + +Belum ada issue terdokumentasi. diff --git a/Dockge/docs/project-status.md b/Dockge/docs/project-status.md new file mode 100644 index 0000000..e207ef5 --- /dev/null +++ b/Dockge/docs/project-status.md @@ -0,0 +1,8 @@ +# Project Status — Dockge + +Docker stack manager — dockge.gisportal.id; primary .24 + agents remote + +| Item | Status | +|------|--------| +| Dokumentasi bootstrap | Done 2026-07-06 | +| Operasional | Lihat server.md | diff --git a/Dockge/docs/server.md b/Dockge/docs/server.md new file mode 100644 index 0000000..dce9355 --- /dev/null +++ b/Dockge/docs/server.md @@ -0,0 +1,45 @@ +# Server — Dockge + +> **Last updated:** 2026-07-06 + +## Primary (`.24`) + +| Item | Nilai | +|------|-------| +| URL | `https://dockge.gisportal.id` | +| Host | `10.100.1.24` | +| Stacks path | `/opt/stacks/` | +| Versi | Dockge v1.5.0 | + +## Remote agent (Mailcow `.28`) + +| Item | Nilai | +|------|-------| +| Agent URL | `http://10.100.1.28:5001` | +| Stack | `/opt/stacks/mailcow` | +| Firewall | port 5001 dari `.24` saja | + +--- + +## Stacks utama (`/opt/stacks/`) + +| Stack | Host | Repo docs | +|-------|------|-----------| +| geonet-console | `.24` | server-connection | +| zammad | `.24` | Zammad | +| mailcow | `.28` | Mailcow | +| geonet-collector | `.24` | GeoNetAgent | +| databaselist | `.24` | server-connection | + +Setiap deploy stack → append [version.md](./version.md) di repo terkait. + +--- + +## SSH + +```bash +ssh reverse-proxy # .24 primary +ssh mailcow # .28 agent +``` + +Credential: env server — jangan di docs. diff --git a/Dockge/docs/system-requirements.md b/Dockge/docs/system-requirements.md new file mode 100644 index 0000000..5d422da --- /dev/null +++ b/Dockge/docs/system-requirements.md @@ -0,0 +1,8 @@ +# System Requirements — Dockge + +| Field | Value | +|-------|-------| +| Stack | Dockge v1.5.0, /opt/stacks/ | +| Host | 10.100.1.24 | + +Env: [../.env.example](../.env.example) diff --git a/Dockge/docs/todo.md b/Dockge/docs/todo.md new file mode 100644 index 0000000..93a374a --- /dev/null +++ b/Dockge/docs/todo.md @@ -0,0 +1,9 @@ +# TODO — Dockge + +## High + +- [ ] Verifikasi config live vs dokumentasi repo + +## Selesai + +- [x] Bootstrap AI-Agent-Standards 2026-07-06 diff --git a/Dockge/docs/version.md b/Dockge/docs/version.md new file mode 100644 index 0000000..d0e7930 --- /dev/null +++ b/Dockge/docs/version.md @@ -0,0 +1,10 @@ +# Version History + +## [1.5.0] - 2026-07-06 + +- Bootstrap dokumentasi AI-Agent-Standards +- Primary Dockge di .24; agent Mailcow .28:5001 + +## [1.5.0-deploy] - 2026-07-03 + +- Dockge agent terpasang di VM Mailcow diff --git a/GeoNetAgent/AGENTS.md b/GeoNetAgent/AGENTS.md index 6079d1b..09896ca 100644 --- a/GeoNetAgent/AGENTS.md +++ b/GeoNetAgent/AGENTS.md @@ -1,84 +1,41 @@ -# AGENTS.md — AI Agent Rules +# AGENTS.md — Cold Start -## Entry Point Wajib +> Project: `GeoNetAgent/` +> Sesi terakhir: [docs/ai-session-summary.md](./docs/ai-session-summary.md) +> Peta lengkap: [docs/context-index.md](./docs/context-index.md) +> Env template: [.env.example](./.env.example) -Sebelum melakukan pekerjaan apa pun, baca berurutan: -1. `docs/context-index.md` — peta seluruh dokumentasi -2. `.cursor/blueprint.md` — visi, fase, batas modul -3. `.cursor/progress.md` — fase aktif & checklist DoD -4. Dokumen spesifik modul (db-schema, api-contracts, dll) +## Apa ini? -**Jangan implement fase N+1 jika fase N belum DoD.** +IT asset monitoring & CMDB ringan: Windows PowerShell agent → FastAPI collector → PostgreSQL. Melengkapi Zabbix. ---- +## Aturan kritis -## Aturan Kode +- **No hardcoded URL/domain/IP** — baca dari `.env` / `.env.example` +- Jangan commit `.env`; credentials di server saja +- No commit kecuali user minta eksplisit +- **Deploy agent:** bump `agent/VERSION` + append [docs/version.md](./docs/version.md) + publish script +- Jangan implement fase N+1 jika fase N belum DoD (`.cursor/progress.md`) +- SSH butuh approval user; SCP pakai `-o "MACs=hmac-sha1"` dari Windows +- Pengetahuan penting **wajib ke docs**, bukan chat -### Python (FastAPI Collector) -- Gunakan `snake_case` untuk variable, function, file -- Type hints wajib di semua function signature -- Pydantic schema di `app/schemas/` — jangan inline model di routes -- Route di `app/api/` — satu file per resource -- DB session via dependency injection (`get_db`) -- Jangan commit `.env` — gunakan `.env.example` +## Lanjut kerja -### PowerShell (Agent) -- Module di `agent/lib/` — satu file per sensor (Get-CpuInfo.ps1, dll) -- Jangan hardcode credential di skrip -- Hindari literal `$env:` di file `.ps1` yang di-serve Nginx (nginx potong respons) -- Test lokal dulu sebelum publish ke `agent.gisportal.id/install/` - -### SQL / Database -- PK: UUID (`gen_random_uuid()`) -- Timestamp: `timestamptz` -- Nama tabel: `snake_case` plural -- Setiap perubahan schema → update `docs/database.md` + `.cursor/db-schema.md` -- Migration order: lihat `infra/db/README.md` - ---- - -## Aturan Deploy - -**Wajib setelah bump versi agent:** -```powershell -.\infra\collector\publish_agent_install.ps1 # upload ke agent.gisportal.id/install/ -.\infra\collector\push_collector.ps1 # rebuild UI/API jika berubah +``` +1. AGENTS.md +2. docs/ai-session-summary.md +3. STOP +4. On-demand: docs/todo.md, docs/issues.md, .cursor/blueprint.md, docs/server.md ``` -- Update `agent/VERSION` + `agent/install/manifest.json` sebelum publish -- Update `Riwayat milestone` di `.cursor/progress.md` -- Update `Sync terakhir` di `perintah.md` - -**File transfer ke server:** gunakan `scp -o "MACs=hmac-sha1"` dari Windows. -Jangan heredoc SSH dari PowerShell — `$` variabel terpotong. - ---- - -## Aturan Dokumentasi - -- Setiap perubahan arsitektur → buat ADR baru di `docs/adr/ADR-00N-*.md` -- ADR **tidak boleh dihapus** — buat ADR baru jika keputusan berubah -- Setelah implementasi: update `.cursor/progress.md` + `perintah.md` -- Implementasi tanpa dokumentasi = **belum selesai** -- Update `docs/context-index.md` jika ada dokumen baru - ---- - -## Aturan Keamanan - -- **Jangan commit secret**: password DB, bearer token, API key -- Credentials DB ada di `/root/geonetagent_dev.credentials` di server 10.100.1.25 -- Token agent ada di `.env` server — lihat `docs/environment.md` untuk nama variabelnya -- SSH command butuh approval user sebelum dijalankan -- Nginx `agent.gisportal.id`: `ssi off` — jangan taruh `$env:` literal di file `.ps1` yang di-serve - ---- +Detail kode: `.cursor/rules` equivalent via `.cursor/blueprint.md`, `docs/development.md`. -## Batas Sistem (Non-goals) +## Pointer cepat -Jangan implement hal-hal berikut — sudah diputuskan di ADR/blueprint: -- ❌ Engine monitoring time-series (pakai Zabbix) -- ❌ NMS pengganti MikroTik/Proxmox tools -- ❌ Duplikasi data GIS legacy dari SQL Server -- ❌ Remote desktop / RMM agent -- ❌ Ticketing enterprise penuh (fase awal) +| Butuh | Buka | +|-------|------| +| Priority | [docs/todo.md](./docs/todo.md) | +| Versi / deploy | [docs/version.md](./docs/version.md) | +| Server | [docs/server.md](./docs/server.md) | +| Schema DB | [docs/database.md](./docs/database.md) | +| ADR | [docs/adr/](./docs/adr/) | diff --git a/GeoNetAgent/docs/ai-session-summary.md b/GeoNetAgent/docs/ai-session-summary.md new file mode 100644 index 0000000..bedb112 --- /dev/null +++ b/GeoNetAgent/docs/ai-session-summary.md @@ -0,0 +1,25 @@ +# AI Session Summary + +```yaml +session: 2026-07-06-docs-bootstrap +project: GeoNetAgent/ +version: 0.1.12-phase0 +status: ready +next: Lanjutkan fase aktif di .cursor/progress.md +agent: Cursor +``` + +## TL;DR + +- Bootstrap docs AI-Agent-Standards: version.md, system-requirements.md, guide/, ai-session-summary +- Agent live `v0.1.12-phase0`; collector di `10.100.1.24` + +## Lanjut dari sini + +1. Baca `.cursor/progress.md` untuk fase aktif +2. Bump versi agent → append `docs/version.md` + publish + +## Jangan + +- Jangan hardcode credential di skrip PowerShell +- Jangan commit `.env` diff --git a/GeoNetAgent/docs/changelog.md b/GeoNetAgent/docs/changelog.md new file mode 100644 index 0000000..9887992 --- /dev/null +++ b/GeoNetAgent/docs/changelog.md @@ -0,0 +1,21 @@ +# Changelog — GeoNetAgent + +Ringkasan per versi: [version.md](./version.md). + +--- + +## [Unreleased] + +--- + +## [0.1.12-phase0] - 2026-06-29 + +### Changed +- Agent sensors & manifest update + +--- + +## [0.1.0] - 2026-07-06 + +### Added +- Bootstrap AI-Agent-Standards (version.md, system-requirements.md, guide/) diff --git a/GeoNetAgent/docs/context-index.md b/GeoNetAgent/docs/context-index.md index fe5ef26..02af1b2 100644 --- a/GeoNetAgent/docs/context-index.md +++ b/GeoNetAgent/docs/context-index.md @@ -1,7 +1,8 @@ # Context Index — GeoNetAgent ⭐ AI Entry Point -> **Terakhir Diperbarui:** 2026-06-29 -> **Versi Agent:** v0.1.10-phase0 +> **Terakhir Diperbarui:** 2026-07-06 +> **Versi Agent:** v0.1.12-phase0 — [version.md](./version.md) +> **Cold start:** [../AGENTS.md](../AGENTS.md) > **Fase Aktif:** Fase 1 — Foundation 🔄 --- diff --git a/GeoNetAgent/docs/guide/README.md b/GeoNetAgent/docs/guide/README.md new file mode 100644 index 0000000..375021c --- /dev/null +++ b/GeoNetAgent/docs/guide/README.md @@ -0,0 +1,6 @@ +# Guides — GeoNetAgent + +| Guide | Path | Kapan | +|-------|------|-------| +| Migrasi server/domain | [migration.md](./migration.md) | Pindah collector/nginx | +| Deploy | [../deployment.md](../deployment.md) | Install stack | diff --git a/GeoNetAgent/docs/guide/migration.md b/GeoNetAgent/docs/guide/migration.md new file mode 100644 index 0000000..e1c676b --- /dev/null +++ b/GeoNetAgent/docs/guide/migration.md @@ -0,0 +1,19 @@ +# Migration Guide — GeoNetAgent + +Inventori: [../server.md](../server.md). Env: [../../.env.example](../../.env.example). + +## Host saat ini + +| Komponen | Host | +|----------|------| +| Collector + nginx | `10.100.1.24` | +| PostgreSQL | `10.100.1.25` | +| Agent install URL | `agent.gisportal.id` | + +## Checklist migrasi + +1. Deploy collector ke host baru +2. Update DNS/nginx → `collector.gisportal.id`, `agent.gisportal.id` +3. Update `.env` + `agent/install` manifest URL +4. Re-publish agent (`publish_agent_install.ps1`) +5. Append [../version.md](../version.md) diff --git a/GeoNetAgent/docs/system-requirements.md b/GeoNetAgent/docs/system-requirements.md new file mode 100644 index 0000000..7b9d867 --- /dev/null +++ b/GeoNetAgent/docs/system-requirements.md @@ -0,0 +1,26 @@ +# System Requirements — GeoNetAgent + +| Field | Value | +|-------|-------| +| Project | `GeoNetAgent/` | +| Tipe | app (agent + API) | +| Last updated | 2026-07-06 | + +## Runtime + +| Tool | Minimum | Dipakai | +|------|---------|---------| +| Python | 3.11+ | FastAPI collector | +| PostgreSQL | 15+ | `10.100.1.25` | +| Docker | 24+ | Collector stack `.24` | +| PowerShell | 5.1+ | Windows agent | +| nginx | 1.24+ | `agent.gisportal.id` | + +## Variabel env (no hardcode) + +| Variabel | Contoh | File | +|----------|--------|------| +| `COLLECTOR_API_URL` | `https://collector.gisportal.id` | `.env.example` | +| `DATABASE_URL` | PostgreSQL `.25` | collector `.env` | + +Detail: [environment.md](./environment.md), [server.md](./server.md). diff --git a/GeoNetAgent/docs/version.md b/GeoNetAgent/docs/version.md new file mode 100644 index 0000000..c5f5d3b --- /dev/null +++ b/GeoNetAgent/docs/version.md @@ -0,0 +1,23 @@ +# Version History + +**Owner:** riwayat versi deploy GeoNetAgent. Append per perubahan material. + +--- + +## [0.1.12-phase0] - 2026-06-29 + +- Agent version bump (lihat `agent/VERSION`) +- Collector/nginx di `10.100.1.24` + +--- + +## [0.1.0] - 2026-06-15 + +- Bootstrap dokumentasi AI-Agent-Standards (version.md, guide/, system-requirements.md) +- Agent phase0 foundation + +--- + +## [0.1.0-docs] - 2026-06-01 + +- Inisialisasi dokumentasi repo (`docs/`, ADR-001–003) diff --git a/GeoNetAgent/infra/nginx/geonetagent-collector-public.conf b/GeoNetAgent/infra/nginx/geonetagent-collector-public.conf index 49c3791..c69a88f 100644 --- a/GeoNetAgent/infra/nginx/geonetagent-collector-public.conf +++ b/GeoNetAgent/infra/nginx/geonetagent-collector-public.conf @@ -66,6 +66,6 @@ server { location / { default_type application/json; - return 404 '{"error":{"code":"NOT_FOUND","message":"Not found"}}'; + return 404 "{\"error\":{\"code\":\"NOT_FOUND\",\"message\":\"Not found\"}}"; } } diff --git a/Mailcow/.env.example b/Mailcow/.env.example index eca470d..ff0c3c6 100644 --- a/Mailcow/.env.example +++ b/Mailcow/.env.example @@ -33,7 +33,7 @@ MAILCOW_SUPPORT_PASSWORD= # Domain email # ============================================================================= MAILCOW_DOMAIN_PRIMARY=geonet.co.id -MAILCOW_DOMAIN_SECONDARY=gegeo.my.id +MAILCOW_DOMAIN_SECONDARY=gisportal.id # ============================================================================= # Port layanan (default Mailcow — jangan ubah kecuali ada konflik) diff --git a/Mailcow/AGENTS.md b/Mailcow/AGENTS.md new file mode 100644 index 0000000..315894b --- /dev/null +++ b/Mailcow/AGENTS.md @@ -0,0 +1,58 @@ +# AGENTS.md — Cold Start + +> Project: `Mailcow/` +> Sesi terakhir: [docs/ai-session-summary.md](./docs/ai-session-summary.md) +> Peta lengkap: [docs/context-index.md](./docs/context-index.md) +> Env template: [.env.example](./.env.example) + +## Apa ini? + +Self-hosted mail server (Mailcow dockerized) untuk `geonet.co.id` + `gisportal.id`. Inbox canonical di `sync.geonet.co.id`; POP3 drain cPanel (geonet); `gisportal.id` langsung ke Mailcow tanpa cPanel. + +## Aturan kritis + +- **No hardcoded URL/domain/IP** — baca dari `.env` / `docs/environment.md` +- Copy `.env.example` → `.env` lokal; **jangan commit** `.env` +- No commit kecuali user minta eksplisit +- **Deploy / rilis:** append [docs/version.md](./docs/version.md) (poin perubahan) + [docs/changelog.md](./docs/changelog.md) +- `support@geonet.co.id` = **authsource ldap** (password AD); fetchmail POP3 tetap dari hosting +- SSH ke server **wajib persetujuan user** (`ssh mailcow` → `10.100.1.28`) +- Pengetahuan penting **wajib ke docs**, bukan hanya chat + +## Lanjut kerja (urutan baca) + +``` +1. AGENTS.md <- Anda di sini +2. docs/ai-session-summary.md <- TL;DR + Lanjut + Jangan +3. STOP - mulai kerja +4. On-demand: + - docs/todo.md + - docs/issues.md + - docs/guide/outlook-imap-setup.md + - docs/guide/migration.md + - docs/system-requirements.md + - docs/server.md + - .env.example + - docs/context-index.md +``` + +**Rolling session memory = hanya** `docs/ai-session-summary.md`. + +## Pointer cepat + +| Butuh | Buka | +|-------|------| +| Priority | [docs/todo.md](./docs/todo.md) | +| Versi / deploy | [docs/version.md](./docs/version.md) | +| Bug / RCA | [docs/issues.md](./docs/issues.md) | +| IMAP client (Outlook) | [docs/guide/outlook-imap-setup.md](./docs/guide/outlook-imap-setup.md) | +| Migrasi MX/domain | [docs/guide/migration.md](./docs/guide/migration.md) | +| Multi-domain gisportal.id | [docs/notes/gisportal-id-mail.md](./docs/notes/gisportal-id-mail.md) | +| Hybrid cPanel geonet | [docs/notes/hybrid-migration-cpanel-mailcow.md](./docs/notes/hybrid-migration-cpanel-mailcow.md) | +| System requirements | [docs/system-requirements.md](./docs/system-requirements.md) | +| Server / infra | [docs/server.md](./docs/server.md) | +| Env vars | [docs/environment.md](./docs/environment.md) | + +## Multi-project + +`Workspace-Context.md` → `AGENTS.md` → `docs/ai-session-summary.md` diff --git a/Mailcow/docs/adr/000-template.md b/Mailcow/docs/adr/000-template.md new file mode 100644 index 0000000..74fd246 --- /dev/null +++ b/Mailcow/docs/adr/000-template.md @@ -0,0 +1,25 @@ +# ADR-000: Template + +> Salin file ini sebagai `ADR-NNN-judul-keputusan.md` saat ada keputusan arsitektur baru. + +## Status + +Proposed | Accepted | Deprecated | Superseded + +## Konteks + +{Masalah atau kebutuhan} + +## Keputusan + +{Apa yang diputuskan} + +## Konsekuensi + +- Positif: ... +- Negatif: ... +- Risiko: ... + +## Referensi + +- [context-index.md](../context-index.md) diff --git a/Mailcow/docs/adr/ADR-0001-support-ldap-auth.md b/Mailcow/docs/adr/ADR-0001-support-ldap-auth.md new file mode 100644 index 0000000..be6c770 --- /dev/null +++ b/Mailcow/docs/adr/ADR-0001-support-ldap-auth.md @@ -0,0 +1,29 @@ +# ADR-0001: support@ authsource LDAP + +## Status + +Accepted — 2026-07-06 + +## Konteks + +- `support@geonet.co.id` perlu diakses user via IMAP dengan **password AD** +- Inbound email SSOT masih cPanel (MX) → fetchmail POP3 drain ke Mailcow +- Mailbox sebelumnya `authsource=mailcow` (service account SQL) + +## Keputusan + +**Satu mailbox** `support@geonet.co.id` dengan `authsource=ldap`: +- fetchmail tetap deliver ke alamat yang sama (tidak terpengaruh auth) +- User PC: IMAP `sync.geonet.co.id:993` + password AD +- Tidak membuat mailbox kedua; tidak copy/move inbox + +## Konsekuensi + +- Positif: satu password AD untuk user; inbox tetap canonical di Mailcow +- Perhatian: SOGo perlu verifikasi setelah switch (`_sogo_static_view`) +- fetchmail POP3 password tetap password **cPanel** (terpisah dari LDAP) +- Zammad channel: gunakan password AD atau app password (dokumentasikan di Zammad) + +## Implementasi + +Script: `scripts/switch-support-to-ldap.sh` diff --git a/Mailcow/docs/ai-session-summary.md b/Mailcow/docs/ai-session-summary.md index 4da30b1..c770e3e 100644 Binary files a/Mailcow/docs/ai-session-summary.md and b/Mailcow/docs/ai-session-summary.md differ diff --git a/Mailcow/docs/changelog.md b/Mailcow/docs/changelog.md index 4025f0d..1c34771 100644 --- a/Mailcow/docs/changelog.md +++ b/Mailcow/docs/changelog.md @@ -1,15 +1,44 @@ # Changelog — Mailcow +Format [Keep a Changelog](https://keepachangelog.com/). Ringkasan: [version.md](./version.md). + +--- + +## [1.2.5] - 2026-07-06 + +### Changed +- SPF `gisportal.id` di Master Web: `v=spf1 a mx ~all` → `v=spf1 ip4:117.102.73.102 -all` + +### Verified +- Propagasi SPF di `dns1.masterweb.com` OK + --- -## 2026-07-03 — fetchmail, SOGo, outbound relay +## [1.2.4] - 2026-07-06 -**Ringkasan:** Email flow support@geonet.co.id end-to-end via Mailcow. +### Added +- Domain `gisportal.id` (Mailcow murni) + `admin@gisportal.id` +- `docs/notes/gisportal-id-mail.md` +- Scripts: `fix-sogo-domain.sh`, `setup-gisportal-inbound-whitelist.sh` -**Fitur:** fetchmail POP3 drain; relay cPanel :587; SOGo operational. +### Fixed +- SOGo Unauthorized (`_sogo_static_view`); inbound forwarding hosts whitelist -**Fix:** SOGo Unauthorized; Gmail 550 smarthost. +--- + +## [1.2.3] - 2026-07-06 + +### Added +- Transport map Jalur B `rbsetiawan@` → cPanel `:587` +- `scripts/setup-transport-cpanel-user.sh` + +### Verified +- `support@` → `rbsetiawan@` (cPanel) OK + +--- -**File:** scripts/install-fetchmail-support.sh, docs/* +## Planned -**Author:** AI Agent (Cursor) +- DKIM `gisportal.id` + `geonet.co.id` +- Zammad IMAP/SMTP channel +- MX cutover geonet.co.id \ No newline at end of file diff --git a/Mailcow/docs/context-index.md b/Mailcow/docs/context-index.md index aba058a..5b91c70 100644 --- a/Mailcow/docs/context-index.md +++ b/Mailcow/docs/context-index.md @@ -1,149 +1,88 @@ -# Context Index — Mailcow ⭐ AI Entry Point +# Context Index — Mailcow -> **Terakhir Diperbarui:** 2026-07-03 -> **Fase Aktif:** Fase 1 — Mailcow live, transisi MX cPanel → sync 📧 - -**Sesi terakhir:** [docs/ai-session-summary.md](./ai-session-summary.md) +> Cold start: [../AGENTS.md](../AGENTS.md) → [ai-session-summary.md](./ai-session-summary.md) → **STOP** --- -## Filosofi - -Proyek ini menerapkan **AI Native Development**: -- Repository = sumber kebenaran utama (Single Source of Truth) -- AI tidak boleh mengandalkan riwayat percakapan -- Developer sering berpindah perangkat — konteks harus tersimpan di repo -- Implementasi tanpa dokumentasi = belum selesai +## Zona A — Always-read pointers + +| Item | Value | +|------|-------| +| Nama | Mailcow | +| Path monorepo | `Mailcow/` | +| Cold start | [../AGENTS.md](../AGENTS.md) | +| Sesi terakhir | [ai-session-summary.md](./ai-session-summary.md) | +| Priority | [todo.md](./todo.md) | +| Server / infra | [server.md](./server.md) | +| System requirements | [system-requirements.md](./system-requirements.md) | +| Env template | [../.env.example](../.env.example) | +| Versi | **1.2.5** — [version.md](./version.md) | +| Stack | Mailcow dockerized, fetchmail (geonet), Dovecot/Postfix | +| Domains | `geonet.co.id` (hybrid cPanel), `gisportal.id` (murni) | +| Tipe | infra | +| Last updated | 2026-07-06 | + +**Rolling session memory:** hanya [ai-session-summary.md](./ai-session-summary.md). --- -## Urutan Membaca +## Zona B — On-demand map -1. **File ini** — peta navigasi -2. **`docs/ai-session-summary.md`** — ringkasan sesi terakhir ⭐ -3. `docs/environment.md` — variabel `.env` (tanpa secret) -3. `.env.example` → copy ke `.env` — isi password & secret -4. Dokumen spesifik task (lihat tabel di bawah) -5. `Zammad/docs/context-index.md` — integrasi email channel - ---- +### Dokumentasi inti -## Posisi dalam Super Apps +| Dokumen | Kapan baca | +|---------|------------| +| [project-status.md](./project-status.md) | Status milestone | +| [issues.md](./issues.md) | Bug / RCA | +| [changelog.md](./changelog.md) | Audit riwayat | +| [version.md](./version.md) | Deploy / rilis | +| [environment.md](./environment.md) | Variabel env | +| [deployment.md](./deployment.md) | Install stack | +| [guide/](./guide/) | IMAP user, migrasi MX | -``` -Internet → MX geonet.co.id → cPanel (staging, inbox kosong setelah POP3) - │ - fetchmail POP3 + delete (VM .27) - ▼ - Mailcow sync.geonet.co.id — inbox canonical (IMAP) - │ │ - Outlook user Zammad - IMAP+SMTP sync IMAP+SMTP sync -``` +### Notes (domain) -| Repo terkait | Entry point | Kapan baca | -|--------------|-------------|------------| -| **Zammad** | `Zammad/docs/context-index.md` | Channel email inbound/outbound | -| **server-connection** | `server-connection/docs/context-index.md` | LDAP AD, nginx pattern | -| **mysupperapps_FE_PWA** | `docs/context-index.md` | Mail UI `/mail` (fase berikutnya) | +| Dokumen | Isi | +|---------|-----| +| [notes/gisportal-id-mail.md](./notes/gisportal-id-mail.md) | Domain `gisportal.id` — Mailcow murni, DNS Master Web | +| [notes/hybrid-migration-cpanel-mailcow.md](./notes/hybrid-migration-cpanel-mailcow.md) | Jalur A/B hybrid geonet | +| [notes/ldap-ad-mailcow.md](./notes/ldap-ad-mailcow.md) | LDAP AD + SOGo troubleshooting | +| [notes/storage-nas-qnap.md](./notes/storage-nas-qnap.md) | Backup QNAP | +| [notes/deployment-sizing.md](./notes/deployment-sizing.md) | Sizing VM | ---- +### Parent / sibling -## Peta Dokumentasi - -### `docs/` — Flat Files - -| File | Isi | Status | Baca Saat | -|------|-----|--------|-----------| -| `docs/context-index.md` | **File ini** — navigasi | ✅ | Selalu | -| `docs/environment.md` | Env vars, port, integrasi Zammad | ✅ | Setup, deploy | -| `docs/project-status.md` | Status modul, milestone | ✅ | Planning | -| `docs/ai-session-summary.md` | **Ringkasan sesi terakhir** | ✅ | Lanjut kerja | -| `docs/roadmap.md` | Fase Mailcow dalam super apps | 📋 | Planning | -| `docs/todo.md` | Next actions berprioritas | ✅ | Sebelum coding | -| `docs/changelog.md` | Riwayat perubahan penting | ✅ | Referensi | -| `docs/issues.md` | Known bugs + workaround | ✅ | Debug | -| `docs/server.md` | Server, SSH, spec VM `.28` | ✅ | Deploy | -| `docs/deployment.md` | Step-by-step install Mailcow | ✅ | Deploy | -| `docs/security.md` | Credential, DNS, port 25 | 📋 | Security | - -### `docs/notes/` - -| File | Isi | -|------|-----| -| `email-sync-migration-concept.md` | **Konsep sync hosting → Mailcow → Zammad** (MX tetap cPanel) | -| `zammad-email-channel.md` | Step-by-step SMTP + IMAP Zammad ↔ Mailcow | -| `dns-cutover-geonet-co-id.md` | MX, SPF, DKIM, DMARC cutover dari cPanel | -| `storage-nas-qnap.md` | **Email di NAS QNAP** — iSCSI / NFS / backup | -| `deployment-sizing.md` | **Linux + Docker, spec VM 30+ user** | -| `ldap-ad-mailcow.md` | **LDAP AD → Mailcow** — auth + provisioning user terpusat | - -### Root repo - -| File | Isi | -|------|-----| -| `.env.example` | Template konfigurasi — **aman di-commit** | -| `.env` | Nilai aktual (password) — **gitignored** | -| `.gitignore` | Exclude secret & data Mailcow | -| `scripts/install-fetchmail-support.sh` | Install POP3 drain + systemd timer | +| Repo | Entry | +|------|-------| +| Zammad | `Zammad/docs/context-index.md` | +| server-connection | `server-connection/docs/context-index.md` | +| nginx | `nginx/docs/context-index.md` | +| Dockge | `Dockge/docs/context-index.md` | --- -## Quick Reference +## Arsitektur singkat -| Fungsi | URL / Path | -|--------|------------| -| Mailcow UI (target) | `https://sync.geonet.co.id` | -| Hostname mail | `sync.geonet.co.id` | -| Mailbox support (fase sync) | `support@sync.geonet.co.id` | -| Mailbox produksi (hosting) | `support@geonet.co.id` @ cPanel | -| Domain utama | `geonet.co.id` (MX tetap hosting) | -| Docker stack (target) | `/opt/stacks/mailcow/` | -| Server Mailcow | `10.100.1.28` (16 vCPU, 32 GB, 2×512 GB SSD) | -| Server Zammad | `10.100.1.24` | - -### Port layanan - -| Port | Layanan | -|------|---------| -| 25 | SMTP inbound | -| 465 | SMTPS | -| 587 | Submission (Zammad outbound) | -| 993 | IMAPS (Zammad inbound) | -| 443 | HTTPS Web UI | - -### SSH - -```bash -ssh mailcow # 10.100.1.28 +``` +geonet.co.id → MX cPanel → fetchmail POP3 → Mailcow (hybrid, transport maps) +gisportal.id → MX mail.gisportal.id → 117.102.73.102 → Mailcow (murni) + ├── Outlook IMAP :993 / SMTP :587 (sync.geonet.co.id) + └── Zammad IMAP (planned) ``` -> SSH ke server **wajib minta persetujuan user** sebelum dijalankan. - ---- - -## Status saat ini (2026-07-03) - -| Item | Status | -|------|--------| -| Mailcow stack `/opt/stacks/mailcow` | ✅ | -| Domain `geonet.co.id` + DKIM generated | ✅ | -| fetchmail POP3 drain `support@` | ✅ timer 2 menit | -| Outbound relay cPanel `:587` | ✅ transisi | -| SOGo kirim/terima `support@` | ✅ verified user | -| LDAP IdP (user AD lain) | ✅ | -| Zammad → Mailcow channel | ❌ | -| DKIM/SPF DNS publish | ❌ | -| MX cutover ke sync | ❌ | - -Detail: [project-status.md](./project-status.md) +| Fungsi | URL / Host | +|--------|------------| +| Mailcow UI | `https://sync.geonet.co.id` | +| VM | `10.100.1.28` | +| IMAP/SMTP | `sync.geonet.co.id` :993 / :587 | +| DNS gisportal | Master Web (`dns1.masterweb.com`) | --- -## Aturan Utama AI +## Aturan kritis AI -1. Baca `docs/context-index.md` ini terlebih dahulu -2. **Jangan commit** `.env` — hanya update `.env.example` (placeholder) dan `docs/environment.md` -3. Integrasi Zammad → referensi `Zammad/docs/` — jangan duplikasi panjang -4. LDAP umum → referensi `server-connection/docs/environment.md` -5. Setelah deploy → buat/update `docs/deployment.md` + `docs/project-status.md` +- No commit `.env`; update `.env.example` + `environment.md` +- Deploy material → append `version.md` + `changelog.md` +- `support@` = authsource **ldap**; `admin@gisportal.id` = **mailcow** +- Jangan masukkan user ke `Mail-Users` jika masih baca cPanel +- SSH wajib persetujuan user diff --git a/Mailcow/docs/environment.md b/Mailcow/docs/environment.md index 83f9749..a4365ec 100644 --- a/Mailcow/docs/environment.md +++ b/Mailcow/docs/environment.md @@ -42,8 +42,8 @@ | Variable | Contoh | Keterangan | |----------|--------|------------| -| `MAILCOW_DOMAIN_PRIMARY` | `geonet.co.id` | Domain utama | -| `MAILCOW_DOMAIN_SECONDARY` | `gegeo.my.id` | Domain tambahan (multi-domain) | +| `MAILCOW_DOMAIN_PRIMARY` | `geonet.co.id` | Domain hybrid (MX masih cPanel, transisi Mailcow) | +| `MAILCOW_DOMAIN_SECONDARY` | `gisportal.id` | Domain Mailcow murni — MX langsung ke `117.102.73.102`, **tanpa cPanel** | --- @@ -131,12 +131,22 @@ Error historis DNS container: `Zammad/docs/notes/email-geonet-co-id.md` ## DNS (panel domain — bukan env Mailcow) +### gisportal.id (Mailcow murni, tanpa cPanel) + +| Record | Nilai | +|--------|-------| +| MX | `10 mail.gisportal.id` | +| A `mail.gisportal.id` | `117.102.73.102` | +| SPF | `v=spf1 ip4:117.102.73.102 -all` | +| DKIM | dari Mailcow Admin → domain `gisportal.id` | + +### geonet.co.id (hybrid, transisi) + | Variable | Contoh | Record | |----------|--------|--------| -| `DNS_MX_HOST` | `mail.gisportal.id` | MX → IP publik server | -| `DNS_SPF_INCLUDE` | `include:mail.gisportal.id` | TXT SPF | -| — | *(dari Mailcow UI)* | TXT DKIM | -| — | | TXT DMARC | +| `DNS_MX_HOST` | `sync.geonet.co.id` | MX setelah cutover | +| SPF | | tambah `ip4:117.102.73.102` saat cutover | +| DKIM | | dari Mailcow UI | --- diff --git a/Mailcow/docs/guide/README.md b/Mailcow/docs/guide/README.md new file mode 100644 index 0000000..ecdd92f --- /dev/null +++ b/Mailcow/docs/guide/README.md @@ -0,0 +1,14 @@ +# Guides — Mailcow + +**Owner:** runbook operasional Mailcow. + +## Indeks + +| Guide | Path | Kapan dipakai | +|-------|------|---------------| +| IMAP/SMTP Outlook user | [outlook-imap-setup.md](./outlook-imap-setup.md) | Setup email di PC user | +| Migrasi MX / domain | [migration.md](./migration.md) | Cutover cPanel → Mailcow | +| Deploy Mailcow | [../deployment.md](../deployment.md) | Install / reinstall stack | +| Email sync concept | [../notes/email-sync-migration-concept.md](../notes/email-sync-migration-concept.md) | Arsitektur POP3 drain | +| Zammad channel | [../notes/zammad-email-channel.md](../notes/zammad-email-channel.md) | Integrasi ticketing | +| LDAP AD | [../notes/ldap-ad-mailcow.md](../notes/ldap-ad-mailcow.md) | User AD → mailbox | diff --git a/Mailcow/docs/guide/migration.md b/Mailcow/docs/guide/migration.md new file mode 100644 index 0000000..73f60ae --- /dev/null +++ b/Mailcow/docs/guide/migration.md @@ -0,0 +1,91 @@ +# Migration Guide — Mailcow (MX & Domain) + +**Owner:** cutover email `geonet.co.id` dari cPanel ke Mailcow. +Inventori: [../server.md](../server.md). Env: [../../.env.example](../../.env.example). + +**Prinsip:** URL/domain dynamic via `.env` — bukan hardcode di script. + +--- + +## Status migrasi saat ini (2026-07-06) + +| Fase | Status | Keterangan | +|------|--------|------------| +| Mailcow live | ✅ | VM `10.100.1.28`, `sync.geonet.co.id` | +| POP3 drain | ✅ | fetchmail timer 2 menit, `nokeep` | +| Outbound relay | ✅ Transisi | cPanel SMTP :587 | +| MX DNS | ❌ | Masih cPanel | +| DKIM/SPF publish | ❌ | Key generated, belum DNS | +| fetchmail mati | ❌ | Setelah MX cutover | + +--- + +## Inventori sebelum cutover MX + +| Item | Saat ini | Target | File update | +|------|----------|--------|-------------| +| MX record | cPanel | `sync.geonet.co.id` | DNS panel | +| Inbox canonical | Mailcow (via POP3) | Mailcow (langsung) | — | +| SPF | cPanel IP | Mailcow `117.102.73.102` | DNS | +| DKIM | — | Mailcow selector | DNS | +| PTR | TBD | `sync.geonet.co.id` | Provider IP | +| fetchmail | aktif | **stop** | systemd disable | +| relay cPanel | aktif | opsional mati | Mailcow relayhosts | + +--- + +## Fase 1 — Transisi (saat ini) + +1. MX tetap cPanel +2. fetchmail POP3 drain → Mailcow inbox +3. User Outlook → IMAP `sync.geonet.co.id:993` saja +4. Outbound relay cPanel sampai reputasi IP Mailcow OK + +Verifikasi fetchmail: +```bash +ssh mailcow +systemctl status fetchmail-support.timer +tail -20 /var/log/fetchmail-support.log +``` + +--- + +## Fase 2 — DNS email publish + +1. [ ] Ambil DKIM public key: Mailcow Admin → Configuration → DKIM +2. [ ] Publish TXT DKIM di DNS `geonet.co.id` +3. [ ] Update SPF: `v=spf1 ip4:117.102.73.102 include:... -all` +4. [ ] Tambah DMARC (opsional): `_dmarc.geonet.co.id` +5. [ ] PTR `117.102.73.102` → `sync.geonet.co.id` +6. [ ] Smoke test: kirim ke Gmail, cek header SPF/DKIM pass + +Append [../version.md](../version.md) setelah publish. + +--- + +## Fase 3 — MX cutover + +1. [ ] Stabil minimal 2–4 minggu (fetchmail + relay tanpa error) +2. [ ] Turunkan TTL MX 24 jam sebelumnya +3. [ ] Ubah MX → `sync.geonet.co.id` (priority 10) +4. [ ] Monitor Postfix log Mailcow 24–48 jam +5. [ ] `systemctl disable --now fetchmail-support.timer` +6. [ ] Evaluasi matikan relay cPanel (kirim langsung dari Mailcow) +7. [ ] Update docs: server.md, project-status.md, version.md + +--- + +## Rollback MX + +1. Kembalikan MX ke cPanel +2. Enable fetchmail timer jika masih diperlukan +3. Catat di [../issues.md](../issues.md) + +--- + +## Riwayat migrasi + +| Tanggal | Dari | Ke | Versi | Catatan | +|---------|------|-----|-------|---------| +| 2026-07-03 | — | POP3 drain live | 1.0.0 | fetchmail + relay | +| 2026-07-06 | — | Docs bootstrap | 1.1.0 | SSOT AI-Agent-Standards | diff --git a/Mailcow/docs/guide/outlook-imap-setup.md b/Mailcow/docs/guide/outlook-imap-setup.md new file mode 100644 index 0000000..4f5d025 --- /dev/null +++ b/Mailcow/docs/guide/outlook-imap-setup.md @@ -0,0 +1,77 @@ +# Guide — Outlook IMAP/SMTP ke Mailcow + +**Untuk:** PC user yang memakai `support@geonet.co.id` (atau mailbox `@geonet.co.id` lain). +**Server:** Mailcow `sync.geonet.co.id` — **bukan** `mail.geonet.co.id` (cPanel). + +--- + +## Pengaturan + +| Setting | Nilai | +|---------|-------| +| Email / Username | `support@geonet.co.id` | +| Password | Password **Active Directory** (Windows login `support` / `support@geonet.co.id`) | +| Incoming | IMAP | +| Server IMAP | `sync.geonet.co.id` | +| Port IMAP | `993` | +| Enkripsi IMAP | SSL/TLS | +| Outgoing | SMTP | +| Server SMTP | `sync.geonet.co.id` | +| Port SMTP | `587` (STARTTLS) — **bukan** SSL/TLS di port 587 | +| Alternatif SMTP | Port `465` + **SSL/TLS** (jika 587 gagal) | +| Auth SMTP | Ya — sama dengan IMAP | + +> `support@` pakai **authsource ldap** (grup AD `Mail-Users`, atribut `mail`). Inbound tetap via fetchmail POP3 dari hosting. + +--- + +## Outlook (Windows) + +1. **File → Add Account** → **Advanced setup** → **IMAP** +2. Incoming: `sync.geonet.co.id`, port **993**, SSL/TLS +3. Outgoing: `sync.geonet.co.id`, port **587**, STARTTLS +4. **More settings → Outgoing Server:** centang SMTP requires authentication, use same as incoming +5. Hapus akun lama jika masih `mail.geonet.co.id` + +--- + +## Thunderbird + +Manual config: IMAP 993 SSL, SMTP 587 STARTTLS, Normal password, username email penuh. + +--- + +## Alur email masuk (transisi) + +``` +Internet → MX cPanel → inbox cPanel + ↓ fetchmail POP3 (~2 menit) + inbox Mailcow → Outlook (IMAP) +``` + +User **tidak** perlu setting POP3 di PC — hanya IMAP ke Mailcow. + +--- + +## Troubleshooting + +| Gejala | Cek | +|--------|-----| +| Auth gagal | Password **AD** (bukan password Mailcow lama); pastikan user di grup `Mail-Users` | +| SMTP encryption error | Port **587** harus **STARTTLS** (bukan SSL/TLS). Port **465** pakai SSL/TLS | +| Cert error / encryption failed | Pastikan cert Let's Encrypt terpasang (`scripts/sync-ssl-from-nginx.sh`) | +| Email tidak masuk | MX masih cPanel — cek fetchmail: `tail /var/log/fetchmail-support.log` | +| Port blocked | `Test-NetConnection sync.geonet.co.id -Port 993` | + +Detail server: [../server.md](../server.md), [../issues.md](../issues.md). + +--- + +## Verifikasi koneksi (PowerShell) + +```powershell +Test-NetConnection sync.geonet.co.id -Port 993 +Test-NetConnection sync.geonet.co.id -Port 587 +``` + +Keduanya harus `TcpTestSucceeded : True`. diff --git a/Mailcow/docs/issues.md b/Mailcow/docs/issues.md index 10f76a4..80282c3 100644 --- a/Mailcow/docs/issues.md +++ b/Mailcow/docs/issues.md @@ -1,23 +1,19 @@ # Issues — Mailcow ---- +## Open -## Open Issues +### ISS-001: _sogo_static_view auto-sync -### ISS-001: _sogo_static_view tidak auto-sync setelah edit password +### ISS-008: Cross-domain gisportal.id ↔ geonet.co.id (2026-07-06) -| Field | Value | -|-------|-------| -| Status | Open | -| Severity | Medium | -| Found | 2026-07-03 | +- `admin@gisportal.id` → user cPanel-only `@geonet.co.id`: cPanel reject (From vs SMTP auth) +- `rianjawa93@geonet.co.id` tidak ada di Mailcow +- Doc: [notes/gisportal-id-mail.md](./notes/gisportal-id-mail.md) -**Workaround:** UPDATE _sogo_static_view FROM mailbox.password; restart sogo container. +## Resolved ---- - -## Resolved Issues - -### ISS-003: SOGo Unauthorized — authsource mailcow + sync view (2026-07-03) -### ISS-004: Gmail 550 — relay sc138:587 (2026-07-03) -### ISS-005: fetchmailrc parse — ssl after user, no sslcertck (2026-07-03) +- ISS-006 Internal mail cPanel user — transport Jalur B `rbsetiawan@` (2026-07-06) +- ISS-003 SOGo Unauthorized (2026-07-03) +- ISS-004 Gmail 550 relay (2026-07-03) +- ISS-005 fetchmail SSL (2026-07-03) +- ISS-007 Outlook SMTP cert (2026-07-06) \ No newline at end of file diff --git a/Mailcow/docs/notes/gisportal-id-mail.md b/Mailcow/docs/notes/gisportal-id-mail.md new file mode 100644 index 0000000..04ad683 --- /dev/null +++ b/Mailcow/docs/notes/gisportal-id-mail.md @@ -0,0 +1,130 @@ +# gisportal.id — Multi-Domain Mail (Mailcow murni) + +> **Penting:** `gisportal.id` **tidak punya cPanel**. Domain ini langsung publik → `117.102.73.102` → port email di-forward ke Mailcow (`10.100.1.28`). +> +> Berbeda dengan `geonet.co.id` yang masih **hybrid** (MX/inbox banyak user di cPanel). + +--- + +## Arsitektur dua domain di satu Mailcow + +``` + ┌─────────────────────────────────────┐ + │ Mailcow sync.geonet.co.id (.28) │ + │ IP publik: 117.102.73.102 │ + └─────────────────────────────────────┘ + ▲ ▲ + MX mail.gisportal.id MX geonet.co.id (masih cPanel) + (langsung ke .102) + fetchmail / transport map + │ │ + gisportal.id │ │ geonet.co.id + (NO cPanel) │ │ (hybrid cPanel) + │ │ + admin@gisportal.id support@, rbsetiawan@, … +``` + +| Domain | Hosting email | Inbound | Outbound | +|--------|---------------|---------|----------| +| **gisportal.id** | **Mailcow saja** | MX → `.102` → Mailcow | Langsung dari Mailcow (tanpa relay cPanel) | +| **geonet.co.id** | Hybrid | MX masih cPanel + fetchmail / transport | Relay cPanel `:587` (transisi) | + +Di Mailcow Admin, domain `gisportal.id` harus **`relayhost` = none** (bukan relay cPanel seperti `geonet.co.id`). + +--- + +## DNS `gisportal.id` — wajib disesuaikan + +SPF saat ini masih mencantumkan **IP cPanel lama** — itu salah untuk domain tanpa cPanel. + +| Record | Target | Status | +|--------|--------|--------| +| MX | `10 mail.gisportal.id` | ✅ | +| A `mail.gisportal.id` | `117.102.73.102` | ✅ | +| A `gisportal.id` | `117.102.73.102` (web) | ✅ | +| **SPF** | `v=spf1 ip4:117.102.73.102 -all` | ✅ 2026-07-06 (TTL 1800, propagasi ~30 menit) | +| **DKIM** | TXT dari Mailcow Admin | ⏳ publish | +| PTR | `117.102.73.102` → `sync.geonet.co.id` | shared dengan geonet | + +**SPF yang benar** (tanpa cPanel): + +```txt +v=spf1 ip4:117.102.73.102 -all +``` + +**Hapus** entri lama seperti `ip4:103.229.73.23` dan `include:idse.idcloudhosting.com` dari SPF `gisportal.id` — itu sisa hosting lama, bukan Mailcow. + +DKIM: Mailcow Admin → Configuration → Configuration & Details → **ARC/DKIM keys** → domain `gisportal.id` → publish TXT ke DNS. + +--- + +## Perilaku `admin@gisportal.id` + +### Yang sudah OK di server + +| Arah | Contoh | Mekanisme | +|------|--------|-----------| +| Terima internal Mailcow | `support@` → `admin@gisportal.id` | LMTP lokal ✅ | +| Kirim ke internet | `admin@gisportal.id` → Gmail | SMTP langsung Mailcow ✅ | +| Kirim ke diri sendiri | SOGo self-test | ✅ | + +### Masalah yang tersisa (bukan karena gisportal punya cPanel) + +| Gejala | Penyebab sebenarnya | +|--------|---------------------| +| Kirim ke `rbsetiawan@geonet.co.id` gagal | **Penerima** di cPanel (`geonet.co.id` hybrid). Transport map pakai auth `support@geonet.co.id` → cPanel menolak From `@gisportal.id` | +| Kirim ke `rianjawa93@geonet.co.id` gagal | Mailbox tidak ada di Mailcow; tidak ada transport map | +| Kirim ke `support@` saja OK | `support@` punya mailbox aktif di Mailcow | +| Terima dari `rbsetiawan@` sempat ditolak | Email dari **cPanel geonet** lewat spam filter; Rspamd `SPOOFED_UNAUTH` — forwarding hosts sudah ditambahkan | +| Terima dari luar lambat/gagal | Tunggu propagasi SPF baru; pastikan DKIM sudah publish | + +**Kirim ke user `@geonet.co.id` yang masih di cPanel** dari akun `@gisportal.id` memang bermasalah — ini konflik **cross-domain ke hybrid geonet**, bukan masalah hosting gisportal. + +**Solusi kirim ke user cPanel-only `@geonet.co.id`:** + +| Opsi | Keterangan | +|------|------------| +| A | Kirim dari `support@geonet.co.id` (bukan `@gisportal.id`) | +| B | Tambah transport map + kredensial SMTP yang domain-nya cocok (jarang praktis) | +| C | Migrasi penerima ke Mailcow (LDAP / mailbox) | + +--- + +## Inbound ke `@gisportal.id` — alur yang benar + +``` +Pengirim (Gmail / rbsetiawan@cPanel / dll) + → DNS MX gisportal.id = mail.gisportal.id + → 117.102.73.102:25 (forward ke Mailcow) + → Postfix Mailcow → inbox admin@gisportal.id +``` + +Tidak ada hop cPanel untuk domain `gisportal.id`. + +Jika `rbsetiawan@` kirim dari **webmail cPanel geonet**, pastikan penerima `admin@gisportal.id` — MX lookup harus ke `mail.gisportal.id`, bukan lewat relay internal geonet saja. + +--- + +## Checklist + +- [ ] SPF `gisportal.id` → `v=spf1 ip4:117.102.73.102 -all` (hapus IP cPanel lama) +- [ ] DKIM publish dari Mailcow +- [ ] Verifikasi domain `gisportal.id` di Mailcow: **relayhost = none** +- [ ] Tes terima dari Gmail → `admin@gisportal.id` +- [ ] Tes terima dari `support@geonet.co.id` → refresh Inbox SOGo +- [ ] (Opsional) DMARC `_dmarc.gisportal.id` + +--- + +## Script terkait + +| Script | Fungsi | +|--------|--------| +| `scripts/fix-sogo-domain.sh` | Sync password SOGo setelah buat mailbox | +| `scripts/setup-gisportal-inbound-whitelist.sh` | Whitelist NAT/cPanel forwarder untuk inbound | + +--- + +## Referensi + +- [hybrid-migration-cpanel-mailcow.md](./hybrid-migration-cpanel-mailcow.md) — hanya untuk **geonet.co.id** +- [ldap-ad-mailcow.md](./ldap-ad-mailcow.md) — AD domain `gisportal.id` vs mailbox `@geonet.co.id` / `@gisportal.id` diff --git a/Mailcow/docs/notes/hybrid-migration-cpanel-mailcow.md b/Mailcow/docs/notes/hybrid-migration-cpanel-mailcow.md new file mode 100644 index 0000000..9f6c32a --- /dev/null +++ b/Mailcow/docs/notes/hybrid-migration-cpanel-mailcow.md @@ -0,0 +1,128 @@ +# Hybrid Migration — User @geonet.co.id (cPanel vs Mailcow) + +> **Kapan baca:** User masih baca email di cPanel, tapi sudah masuk grup `Mail-Users` / punya mailbox Mailcow. + +--- + +## Masalah + +``` +support@ (Mailcow) --kirim--> rbsetiawan@geonet.co.id + | + Postfix Mailcow: LOCAL delivery + (karena mailbox ada di Mailcow) + | + inbox Mailcow saja + X + inbox cPanel (MX eksternal) +``` + +| Arah email | rbsetiawan baca di | Masuk ke | +|------------|-------------------|----------| +| Internet → MX cPanel | cPanel | ✅ cPanel | +| support@ → rbsetiawan@ (internal Mailcow) | cPanel | ❌ hanya Mailcow | + +**Satu alamat email = satu inbox canonical.** Tidak bisa mailbox aktif di Mailcow **dan** inbox utama di cPanel untuk routing internal. + +--- + +## Dua jalur per user + +### Jalur A — Migrasi penuh ke Mailcow (disarankan jangka panjang) + +Sesuai [`email-sync-migration-concept.md`](./email-sync-migration-concept.md). + +| Step | Aksi | +|------|------| +| 1 | Tetap di grup `Mail-Users` | +| 2 | Mailbox Mailcow aktif (LDAP) | +| 3 | Tambah **fetchmail POP3** dari cPanel → Mailcow (seperti `support@`) | +| 4 | User ganti Outlook → IMAP `sync.geonet.co.id` + password AD | +| 5 | Inbox canonical = **Mailcow saja** | + +Email internal dari `support@` sudah masuk Mailcow — user tinggal baca di sana. + +### Jalur B — Tetap di cPanel (belum migrasi) + +| Step | Aksi | +|------|------| +| 1 | **Keluarkan** user dari grup AD `Mail-Users` | +| 2 | Nonaktifkan mailbox di Mailcow Admin (**Inactive**) | +| 3 | LDAP sync: `docker exec mailcowdockerized-php-fpm-mailcow-1 php /crons/ldap-sync.php` | +| 4 | **Transport map** → relay ke SMTP cPanel (wajib) | +| 5 | Aktifkan alias (jika ada) agar SOGo terima penerima | +| 6 | User tetap baca email di cPanel | + +Tanpa transport map: kirim internal dari Mailcow ke user tanpa mailbox → error `User unknown`. + +#### Transport map (Mailcow Admin UI) + +**Configuration → Routing → Transport maps → Add** + +| Field | Contoh `rbsetiawan@` | +|-------|----------------------| +| Destination | `rbsetiawan@geonet.co.id` | +| Nexthop | `[sc138.idcloudhosting.cloud]:587` | +| Username | `support@geonet.co.id` (sama relay outbound) | +| Password | password SMTP cPanel relay | +| Active | ✅ | + +Atau jalankan script: `scripts/setup-transport-cpanel-user.sh rbsetiawan@geonet.co.id` + +**Catatan:** Port **25** ke cPanel ditolak RBL (IP publik Mailcow). Pakai **587 + auth**. + +Verifikasi Postfix: `postmap -q rbsetiawan@geonet.co.id mysql:/opt/postfix/conf/sql/mysql_transport_maps.cf` → harus return `smtp_via_transport_maps:[sc138...]:587` + +--- + +## Kebijakan tim (rekomendasi) + +| Fase user | Grup `Mail-Users` | Mailbox Mailcow | Baca email via | +|-----------|-------------------|-----------------|----------------| +| **Belum migrasi** | ❌ Jangan tambah dulu | ❌ | cPanel | +| **Migrasi** | ✅ | ✅ | `sync.geonet.co.id` IMAP | +| **support@** | ✅ | ✅ + fetchmail POP3 | Mailcow | + +**Jangan** masukkan semua user ke `Mail-Users` sekaligus jika masih pakai cPanel harian. + +--- + +## Untuk kasus rbsetiawan@ saat ini (Jalur B — diterapkan 2026-07-06) + +| Item | Status | +|------|--------| +| Keluar grup `Mail-Users` | ✅ | +| Mailbox Mailcow Inactive | ✅ (`active=0`) | +| LDAP sync | ✅ | +| Transport map → cPanel :587 | ✅ | +| Alias aktif (SOGo RCPT) | ✅ | +| Tes kirim support@ → rbsetiawan@ | ✅ verified — inbox cPanel | + +Email lama yang sudah masuk inbox Mailcow **tidak otomatis pindah** ke cPanel. + +Untuk migrasi penuh (Jalur A): fetchmail POP3 + Outlook IMAP Mailcow — lihat [`email-sync-migration-concept.md`](./email-sync-migration-concept.md). + +--- + +## fetchmail multi-user + +Contoh tambahan di `/opt/fetchmail/fetchmailrc` (satu entry per user migrasi): + +``` +poll mail.geonet.co.id with proto POP3 port 995 + user "rbsetiawan@geonet.co.id" there with password "..." is "rbsetiawan@geonet.co.id" here + ssl + no sslcertck + smtphost 127.0.0.1 + smtpname sync.geonet.co.id + fetchall + nokeep +``` + +--- + +## Referensi + +- [email-sync-migration-concept.md](./email-sync-migration-concept.md) +- [ldap-ad-mailcow.md](./ldap-ad-mailcow.md) +- [issues.md](../issues.md) ISS-006 diff --git a/Mailcow/docs/notes/ldap-ad-mailcow.md b/Mailcow/docs/notes/ldap-ad-mailcow.md index 9685f58..d318999 100644 --- a/Mailcow/docs/notes/ldap-ad-mailcow.md +++ b/Mailcow/docs/notes/ldap-ad-mailcow.md @@ -1,13 +1,26 @@ # LDAP — Mailcow ke Active Directory -> **Terakhir Diperbarui:** 2026-07-03 +> **Terakhir Diperbarui:** 2026-07-06 > **AD:** `10.100.1.40` · domain `gisportal.id` -> **Status:** Grup AD siap ✅ · LDAP Identity Provider aktif ✅ (2026-07-03) +> **Status:** **26 mailbox** `@geonet.co.id` via LDAP ✅ (2026-07-06) > ⚠️ Bind password **tidak** didokumentasikan di repo — reuse `geonet-console` `.env` --- -## Status AD — Mail-Users (2026-07-03) +## Status AD — Mail-Users (2026-07-06) + +| Item | Nilai | Status | +|------|-------|--------| +| Grup LDAP | `Mail-Users` | ✅ | +| DN grup | `CN=Mail-Users,CN=Users,DC=gisportal,DC=id` | ✅ | +| Mailbox di Mailcow | **26** user `@geonet.co.id` | ✅ LDAP sync | +| Kirim internal | `support@` → `rbsetiawan@` dll. | ✅ verified | + +**Onboard user baru:** tambah ke grup `Mail-Users` + atribut `mail` = `user@geonet.co.id` → jalankan `php /crons/ldap-sync.php` atau tunggu periodic sync (15 menit). + +--- + +## Status AD — Mail-Users (awal 2026-07-03) | Item | Nilai | Status | |------|-------|--------| @@ -216,7 +229,7 @@ Setelah LDAP aktif: | **Outlook** | `user@geonet.co.id` + **password AD** | IMAP/SMTP `sync.geonet.co.id` | | **Zammad channel** | Service account `support@geonet.co.id` | Bisa tetap password mailbox khusus *(bukan LDAP user login)* | -> Mailbox `support@` untuk Zammad/fetchmail bisa tetap **authsource mailcow (SQL)** dengan app password, sementara user biasa pakai LDAP — menghindari konflik service account. +> **Keputusan 2026-07-06:** `support@` memakai **authsource ldap** (satu mailbox). fetchmail POP3 tetap; user IMAP password AD. Lihat [ADR-0001-support-ldap-auth.md](../adr/ADR-0001-support-ldap-auth.md). --- @@ -273,6 +286,9 @@ Pertahankan akun `admin` SQL terpisah — **jangan** pakai LDAP untuk admin pane | Email salah domain | `mail` di AD masih `@gisportal.id` | Update AD → `@geonet.co.id` | | Connection test gagal | Firewall / bind password | `nc` ke `.40:389`, cek bind DN | | Semua user AD dapat mailbox | Filter terlalu luas | Perketat `memberOf=CN=Mail-Users,...` | +| **SOGo Unauthorized** (domain baru) | `_sogo_static_view` password tidak sinkron; domain belum di SOGo plist | Reset password di Admin UI → jalankan `scripts/fix-sogo-domain.sh` | +| **SOGo Unauthorized** (`authsource=mailcow`) | Password SOGo ≠ password mailbox; atau pakai password **AD** salah | Pakai password **Mailcow mailbox** (bukan `Administrator@gisportal.id` AD) | +| `/user` OK, `/SOGo/so/` 403 tanpa login | Session terpisah | Login form SOGo, atau buka Webmail dari menu `/user` | --- diff --git a/Mailcow/docs/project-status.md b/Mailcow/docs/project-status.md index 114f04a..a802b91 100644 --- a/Mailcow/docs/project-status.md +++ b/Mailcow/docs/project-status.md @@ -1,6 +1,7 @@ # Project Status — Mailcow -> **Terakhir Diperbarui:** 2026-07-03 +> **Terakhir Diperbarui:** 2026-07-06 +> **Versi:** 1.2.5 — [version.md](./version.md) --- @@ -10,65 +11,46 @@ |-----------|---------|---------| | **VM IP** | `10.100.1.28` | 2026-07-03 | | **vCPU / RAM** | 16 core / 32 GiB | 2026-07-03 | -| **Disk 1** | 512 GiB SSD — OS + DB | 2026-07-03 | -| **Disk 2** | 512 GiB SSD — vmail live | 2026-07-03 | -| **Prioritas storage** | Uptime layanan mail — local SSD | 2026-07-03 | +| **Dual domain** | `geonet.co.id` hybrid + `gisportal.id` murni | 2026-07-06 | +| **gisportal.id** | Tanpa cPanel; MX langsung ke Mailcow | 2026-07-06 | | **Backup** | QNAP `10.100.1.10` harian | 2026-07-03 | -Mail tetap jalan meski NAS maintenance atau gangguan LAN ke QNAP. - --- ## Ringkasan | Item | Status | |------|--------| -| Dokumentasi repo | ✅ | -| Konsep POP3 drain → Mailcow | ✅ `docs/notes/email-sync-migration-concept.md` | -| Konsep LDAP AD | ✅ `docs/notes/ldap-ad-mailcow.md` | -| Grup AD `Mail-Users` | ✅ 2026-07-03 | -| Member `support` + `mail` | ✅ `support@geonet.co.id` | -| **Storage live** | Local SSD VM + backup QNAP | ✅ Keputusan 2026-07-03 | -| **VM Mailcow** | `10.100.1.28` — 16 vCPU, 32 GB, 2×512 GB SSD | ✅ | -| SSH key login | `ssh mailcow` | ✅ 2026-07-03 | -| OS prep (hostname, disk, docker) | ✅ 2026-07-03 | -| Desktop GNOME (Proxmox console) | ✅ ubuntu-desktop-minimal | -| Install Mailcow stack | ✅ 2026-07-03 — `/opt/stacks/mailcow` | -| Domain `geonet.co.id` | ✅ aktif, DKIM generated | -| Mailbox `support@geonet.co.id` | ✅ auth mailcow (service account) | -| SOGo login + kirim/terima | ✅ verified user 2026-07-03 | -| Outbound relay cPanel | ✅ `sc138.idcloudhosting.cloud:587` | -| Nginx proxy `sync.geonet.co.id` | ✅ `.24` + Let's Encrypt | -| LDAP Identity Provider | ✅ 2026-07-03 (user AD lain) | -| fetchmail POP3 drain | ✅ timer 2 menit — `scripts/install-fetchmail-support.sh` | +| Domain `geonet.co.id` | ✅ hybrid cPanel (fetchmail + relay + transport maps) | +| Domain `gisportal.id` | ✅ Mailcow murni; mailbox `admin@gisportal.id` | +| LDAP 26 mailbox `@geonet.co.id` | ✅ | +| Jalur B `rbsetiawan@` transport | ✅ verified | +| SOGo `admin@gisportal.id` | ✅ | +| Outbound Gmail dari gisportal | ✅ | +| SPF `gisportal.id` (Master Web) | ✅ propagasi OK | +| DKIM `gisportal.id` | ⏳ | +| SPF/DKIM `geonet.co.id` | ⏳ | | Zammad IMAP → Mailcow | ❌ | -| DKIM/SPF DNS publish | ❌ | +| MX cutover geonet | ❌ | --- -## Active Directory — Mail-Users +## Hybrid geonet.co.id -| Item | Nilai | -|------|-------| -| Grup | `Mail-Users` | -| DN (asumsi default) | `CN=Mail-Users,CN=Users,DC=gisportal,DC=id` | -| Member pertama | `support` | -| Email (`mail`) | `support@geonet.co.id` | -| Login AD | `support` (sAMAccountName) | +| Jalur | Deskripsi | Contoh | +|-------|-----------|--------| +| A | Full migrate: Mail-Users + mailbox aktif | `support@` | +| B | cPanel-only: inactive + transport map | `rbsetiawan@` | -> Verifikasi DN grup jika LDAP filter gagal: PowerShell di AD → `(Get-ADGroup 'Mail-Users').DistinguishedName` +Script: `setup-transport-cpanel-user.sh` --- ## Berikutnya -1. Provision VM + Mailcow + LDAP | ✅ -2. Domain `geonet.co.id` + mailbox `support@` | ✅ -3. DNS email (DKIM/SPF) untuk `geonet.co.id` | ⏳ -4. fetchmail POP3 drain dari cPanel | ✅ -5. Outbound relay cPanel (transisi) | ✅ -6. SOGo `support@` operational | ✅ -7. DNS DKIM/SPF + PTR | ⏳ -8. Zammad IMAP/SMTP → Mailcow | ⏳ +1. SPF `gisportal.id` → `v=spf1 ip4:117.102.73.102 -all` (Master Web) +2. DKIM `gisportal.id` + `geonet.co.id` publish +3. Zammad IMAP/SMTP channel +4. MX cutover `geonet.co.id` -Lihat `docs/todo.md`, `docs/ai-session-summary.md`. +Lihat `docs/todo.md`, `docs/ai-session-summary.md`, `docs/notes/gisportal-id-mail.md`. diff --git a/Mailcow/docs/system-requirements.md b/Mailcow/docs/system-requirements.md new file mode 100644 index 0000000..581c7c4 --- /dev/null +++ b/Mailcow/docs/system-requirements.md @@ -0,0 +1,101 @@ +# System Requirements — Mailcow + +**Owner:** runtime minimum agar Mailcow + fetchmail berjalan. +Inventori host: [server.md](./server.md). Env: [.env.example](../.env.example). + +--- + +## Ringkasan + +| Field | Value | +|-------|-------| +| Project | `Mailcow/` | +| Tipe | infra (mail server) | +| Last updated | 2026-07-06 | + +--- + +## Platform & OS + +| Komponen | Minimum | Dipakai saat ini | +|----------|---------|------------------| +| OS server | Ubuntu 22.04 LTS | Ubuntu 22.04.5 LTS | +| Arsitektur | x64 | x64 | +| `vm.max_map_count` | 262144 | 262144 | + +--- + +## Runtime & Toolchain + +| Tool | Minimum | Dipakai | Cek | +|------|---------|---------|-----| +| Docker | 24+ | 29.x | `docker --version` | +| Docker Compose | v2 | v5 | `docker compose version` | +| fetchmail | 6.x | systemd package | `fetchmail -V` | +| systemd | — | timer 2 menit | `systemctl status fetchmail-support.timer` | + +--- + +## Resource minimum (VM Mailcow) + +| Lingkungan | CPU | RAM | Disk | +|------------|-----|-----|------| +| prod (30+ user) | 8 vCPU | 16 GiB | 2×256 GiB SSD | +| prod (saat ini) | **16 vCPU** | **32 GiB** | 2×512 GiB SSD | + +Disk 2: `/data/mailcow/vmail` (Dovecot mail storage live). + +--- + +## Dependency eksternal + +| Dependency | Host | Dipakai untuk | +|------------|------|---------------| +| nginx reverse proxy | `10.100.1.24` | HTTPS UI `sync.geonet.co.id` | +| Active Directory LDAP | `10.100.1.40:389` | Identity Provider (bukan `support@`) | +| cPanel POP3 | `mail.geonet.co.id:995` | fetchmail drain (transisi) | +| cPanel SMTP relay | `sc138.idcloudhosting.cloud:587` | Outbound transisi | +| QNAP NAS | `10.100.1.10` | Backup harian | +| Dockge primary | `10.100.1.24` | Manajemen stack | + +--- + +## Variabel URL & konfigurasi (no hardcode) + +| Variabel | Wajib | Contoh | Dipakai oleh | +|----------|-------|--------|--------------| +| `MAILCOW_HOSTNAME` | ya | `sync.geonet.co.id` | Mailcow generate_config | +| `MAILCOW_VM_IP` | ya | `10.100.1.28` | docs, SSH | +| `MAILCOW_SUPPORT_EMAIL` | ya | `support@geonet.co.id` | fetchmail, Zammad | +| `MAILCOW_SUPPORT_PASSWORD` | ya | *(secret)* | fetchmail, SOGo, SMTP | +| `LDAP_HOST` | opsional | `10.100.1.40` | Identity Provider | +| `LEGACY_SMTP_HOST` | transisi | `sc138.idcloudhosting.cloud` | relay outbound | + +Detail: [environment.md](./environment.md), [.env.example](../.env.example). + +--- + +## Port & protokol + +| Service | Port | Protokol | +|---------|------|----------| +| SMTP inbound | 25 | TCP | +| SMTPS | 465 | TCP/TLS | +| Submission | 587 | TCP/STARTTLS | +| IMAPS | 993 | TCP/TLS | +| POP3S | 995 | TCP/TLS | +| HTTPS (UI) | 443 | HTTPS | +| Dockge agent | 5001 | HTTP (LAN only) | + +--- + +## Client IMAP (PC user) + +| Setting | Nilai | +|---------|-------| +| Server | `sync.geonet.co.id` | +| Port | 993 SSL/TLS | +| Username | `support@geonet.co.id` | +| Password | Password Mailcow (bukan AD) | + +Panduan lengkap: [guide/outlook-imap-setup.md](./guide/outlook-imap-setup.md). diff --git a/Mailcow/docs/todo.md b/Mailcow/docs/todo.md index aa52309..3193af7 100644 --- a/Mailcow/docs/todo.md +++ b/Mailcow/docs/todo.md @@ -1,47 +1,39 @@ # TODO — Mailcow -> Last updated: 2026-07-03 +> Last updated: 2026-07-06 --- ## High Priority -- [ ] Publish DKIM TXT dkim._domainkey.geonet.co.id (key dari Mailcow API) -- [ ] Update SPF geonet.co.id — include IP 117.102.73.102 atau relay sementara -- [ ] Zammad channel email → IMAP/SMTP Mailcow 10.100.1.28 (ganti cPanel) +- [ ] **DKIM `gisportal.id`** publish TXT dari Mailcow Admin → Master Web +- [ ] Verifikasi terima/kirim `admin@gisportal.id` (Gmail ↔ SOGo) setelah DKIM +- [ ] Publish DKIM + SPF `geonet.co.id` +- [ ] Zammad channel email → IMAP/SMTP Mailcow `10.100.1.28` --- ## Medium Priority -- [ ] PTR/rDNS 117.102.73.102 → sync.geonet.co.id -- [ ] Buat scripts/install-relay-cpanel.sh (mirror fetchmail installer) -- [ ] Automasi sync _sogo_static_view setelah password mailbox mailcow berubah -- [ ] Monitoring fetchmail (Uptime Kuma atau alert log) +- [ ] PTR/rDNS `117.102.73.102` → `sync.geonet.co.id` +- [ ] Script `install-relay-cpanel.sh` +- [ ] Auto-sync `_sogo_static_view` setelah ganti password +- [ ] Hapus relayhost id=2 typo di Mailcow Admin (jika masih ada) --- ## Low Priority -- [ ] fetchmail entry untuk mailbox tambahan (info@, dll.) -- [ ] LDAP user lain di Mail-Users — provisioning + Outlook guide -- [ ] Domain sekunder gegeo.my.id -- [ ] MX cutover ke sync.geonet.co.id (setelah 2–4 minggu stabil) -- [ ] Matikan fetchmail + relay cPanel pasca cutover +- [ ] MX cutover `geonet.co.id` → `sync.geonet.co.id` +- [ ] Matikan fetchmail + relay cPanel setelah cutover +- [ ] Transport map `rianjawa93@` jika tetap di cPanel --- -## Selesai (Sesi 2026-07-03) +## Selesai (Sesi Ini) -- [x] fetchmail POP3 drain support@ + timer 2 menit -- [x] Relay outbound cPanel :587 untuk geonet.co.id -- [x] SOGo login + kirim/terima email verified -- [x] scripts/install-fetchmail-support.sh -- [x] Dokumentasi handover sesi - ---- - -## Technical Debt - -- [ ] support@ service account vs LDAP — dokumentasikan keputusan -- [ ] context-index diagram IP — align ke .28 +- [x] Jalur B `rbsetiawan@`: transport map + verified `support@` → cPanel +- [x] Domain `gisportal.id` + mailbox `admin@gisportal.id` + SOGo +- [x] Forwarding hosts whitelist inbound gisportal +- [x] SPF `gisportal.id`: `v=spf1 ip4:117.102.73.102 -all` (Master Web, propagasi OK) +- [x] Scripts + docs dual-domain (`gisportal-id-mail.md`, hybrid migration) diff --git a/Mailcow/docs/version.md b/Mailcow/docs/version.md new file mode 100644 index 0000000..8c19585 --- /dev/null +++ b/Mailcow/docs/version.md @@ -0,0 +1,89 @@ +# Version History + +**Owner:** riwayat versi deploy/config Mailcow — append per perubahan material. +Sinkron dengan [changelog.md](./changelog.md). + +**Wajib sebelum deploy:** append entri baru di sini (bullet poin jelas). + +--- + +## [1.2.5] - 2026-07-06 + +- SPF `gisportal.id` dipublish di Master Web: `v=spf1 ip4:117.102.73.102 -all` + +--- + +## [1.2.4] - 2026-07-06 + +- Dokumentasi `gisportal.id`: domain **Mailcow murni** (tanpa cPanel), langsung `.102` → Mailcow +- SPF `gisportal.id` harus diganti: `v=spf1 ip4:117.102.73.102 -all` (hapus IP cPanel lama) +- Whitelist forwarding hosts untuk inbound dari pengirim cPanel geonet +- Cross-domain `@gisportal.id` → user cPanel-only `@geonet.co.id` tetap terbatas (bukan masalah cPanel gisportal) + +--- + +## [1.2.3] - 2026-07-06 + +- **Jalur B hybrid** `rbsetiawan@geonet.co.id`: keluar `Mail-Users`, mailbox Inactive, transport map ke cPanel +- Transport: `rbsetiawan@geonet.co.id` → `[sc138.idcloudhosting.cloud]:587` (auth `support@`) +- Alias `rbsetiawan@` diaktifkan agar SOGo terima penerima +- Script: `scripts/setup-transport-cpanel-user.sh` +- Port 25 ke cPanel ditolak RBL; wajib relay :587 +- **Verified:** kirim `support@` (Mailcow/LDAP) → `rbsetiawan@` (cPanel) OK + +--- + +## [1.2.2] - 2026-07-06 + +- Semua user `@geonet.co.id` ditambahkan ke grup AD **Mail-Users** +- LDAP sync: **26 mailbox** aktif (`authsource=ldap`) +- Kirim internal `support@` → `rbsetiawan@` verified (SOGo/webmail) +- Kirim eksternal → Gmail verified + +--- + +## [1.2.1] - 2026-07-06 + +- Fix Outlook SMTP: pasang cert **Let's Encrypt** ke Postfix/Dovecot (salin dari nginx `.24`) +- Script: `scripts/sync-ssl-from-nginx.sh` +- Penyebab error: port 587 pakai cert self-signed + Outlook port 587 harus STARTTLS + +--- + +## [1.2.0] - 2026-07-06 + +- `support@geonet.co.id` authsource **mailcow → ldap** (satu mailbox, inbox tidak dipindah) +- User IMAP/SMTP: password **Active Directory** (`Mail-Users`) +- fetchmail POP3 drain **tetap aktif** — inbound SSOT hosting → inbox Mailcow sama +- Script: `scripts/switch-support-to-ldap.sh` +- ADR: `docs/adr/ADR-0001-support-ldap-auth.md` +- Inbox verified: 11 pesan setelah switch + +--- + +## [1.1.0] - 2026-07-06 + +- Bootstrap dokumentasi AI-Agent-Standards (AGENTS.md, version.md, system-requirements.md, guide/) +- Panduan IMAP/SMTP Outlook user → `docs/guide/outlook-imap-setup.md` +- Verifikasi fetchmail POP3 drain aktif (timer 2 menit, inbox Mailcow 9 pesan) +- Perbaikan encoding `changelog.md` / `todo.md` (UTF-8) + +--- + +## [1.0.0] - 2026-07-03 + +- Mailcow stack live di VM `10.100.1.28` (`/opt/stacks/mailcow`) +- Domain `geonet.co.id` + mailbox `support@geonet.co.id` (authsource mailcow) +- fetchmail POP3 drain cPanel → Mailcow (`scripts/install-fetchmail-support.sh`, timer 2 menit) +- Outbound relay cPanel `sc138.idcloudhosting.cloud:587` (transisi, Gmail tidak reject) +- SOGo login + kirim/terima verified +- LDAP Identity Provider untuk user AD (`Mail-Users`) +- Nginx proxy `sync.geonet.co.id` di `10.100.1.24` + Let's Encrypt +- Dockge agent port `5001` di VM Mailcow + +--- + +## [0.1.0] - 2026-07-01 + +- Inisialisasi dokumentasi repo Mailcow +- Konsep POP3 drain + LDAP AD (`docs/notes/`) diff --git a/Mailcow/scripts/fix-sogo-domain.sh b/Mailcow/scripts/fix-sogo-domain.sh new file mode 100644 index 0000000..b518cc8 --- /dev/null +++ b/Mailcow/scripts/fix-sogo-domain.sh @@ -0,0 +1,37 @@ +#!/bin/bash +# Fix SOGo for mailcow-auth mailboxes (authsource=mailcow), especially new domains. +# Run after: new domain/mailbox, password change in Admin UI, or SOGo Unauthorized. +# Usage: fix-sogo-domain.sh [user@domain.tld] +set -euo pipefail +STACK='/opt/stacks/mailcow' +USER="${1:-admin@gisportal.id}" + +echo "== Sync c_password from mailbox (authsource=mailcow) ==" +docker exec mailcowdockerized-mysql-mailcow-1 bash -lc ' +mysql mailcow -uroot -p"$MYSQL_ROOT_PASSWORD" -e " +UPDATE _sogo_static_view s +INNER JOIN mailbox m ON m.username = s.c_name +SET s.c_password = m.password +WHERE m.authsource = \"mailcow\" AND m.active IN (\"1\",\"2\"); +" +' + +echo "== Verify: $USER ==" +docker exec mailcowdockerized-mysql-mailcow-1 bash -lc " +mysql mailcow -uroot -p\"\$MYSQL_ROOT_PASSWORD\" -N -e \" +SELECT 'mailbox', LEFT(password,55) FROM mailbox WHERE username='${USER}'; +SELECT 'sogo', LEFT(c_password,55) FROM _sogo_static_view WHERE c_name='${USER}'; +\" +" + +echo "== Restart SOGo ==" +cd "$STACK" +docker compose restart sogo-mailcow +sleep 8 + +echo "== SOGo domains ==" +docker exec mailcowdockerized-sogo-mailcow-1 grep -E '(geonet|gisportal|gegeo)' /var/lib/sogo/GNUstep/Defaults/sogod.plist || \ + docker exec mailcowdockerized-sogo-mailcow-1 grep '.*\.id' /var/lib/sogo/GNUstep/Defaults/sogod.plist + +echo "" +echo "DONE. Login SOGo with Mailcow mailbox password (NOT AD password for authsource=mailcow)." \ No newline at end of file diff --git a/Mailcow/scripts/setup-gisportal-inbound-whitelist.sh b/Mailcow/scripts/setup-gisportal-inbound-whitelist.sh new file mode 100644 index 0000000..8f1eaa1 --- /dev/null +++ b/Mailcow/scripts/setup-gisportal-inbound-whitelist.sh @@ -0,0 +1,19 @@ +#!/bin/bash +# Fix inbound mail to @gisportal.id from cPanel/NAT path (rspamd SPOOFED_UNAUTH) +set -euo pipefail + +echo "== Add forwarding hosts (trusted inbound relays) ==" +docker exec mailcowdockerized-mysql-mailcow-1 bash -lc ' +mysql mailcow -uroot -p"$MYSQL_ROOT_PASSWORD" -e " +INSERT IGNORE INTO forwarding_hosts (host, source, filter_spam) VALUES + (\"10.100.1.1\", \"NAT gateway inbound\", 1), + (\"103.229.73.23\", \"cPanel sc138\", 1), + (\"sc138.idcloudhosting.cloud\", \"cPanel SMTP hostname\", 1), + (\"spfilter-2.idcloudhosting.com\", \"cPanel spam filter\", 1); +SELECT host, source FROM forwarding_hosts; +" +' + +docker exec mailcowdockerized-postfix-mailcow-1 postfix reload +docker exec mailcowdockerized-rspamd-mailcow-1 rspamadm reload 2>/dev/null || true +echo "DONE forwarding hosts" diff --git a/Mailcow/scripts/setup-transport-cpanel-user.sh b/Mailcow/scripts/setup-transport-cpanel-user.sh new file mode 100644 index 0000000..ed8f16b --- /dev/null +++ b/Mailcow/scripts/setup-transport-cpanel-user.sh @@ -0,0 +1,79 @@ +#!/bin/bash +# Path B hybrid: relay internal mail for a cPanel-only user via transport map. +# Prerequisite: user removed from AD Mail-Users, mailbox inactive in Mailcow Admin. +# Usage: setup-transport-cpanel-user.sh user@geonet.co.id +set -euo pipefail + +EMAIL="${1:-}" +NEXTHOP="${TRANSPORT_NEXTHOP:-[sc138.idcloudhosting.cloud]:587}" +RELAYHOST_ID="${TRANSPORT_RELAYHOST_ID:-1}" + +STACK='/opt/stacks/mailcow' +MYSQL_C='mailcowdockerized-mysql-mailcow-1' +POSTFIX_C='mailcowdockerized-postfix-mailcow-1' +PHP_C='mailcowdockerized-php-fpm-mailcow-1' + +if [ -z "$EMAIL" ]; then + echo "Usage: $0 user@geonet.co.id" + exit 1 +fi + +mysql_q() { + docker exec "$MYSQL_C" bash -lc "mysql mailcow -uroot -p\"\$MYSQL_ROOT_PASSWORD\" -N -e \"$1\"" +} + +mysql_exec() { + docker exec "$MYSQL_C" bash -lc "mysql mailcow -uroot -p\"\$MYSQL_ROOT_PASSWORD\" -e \"$1\"" +} + +echo "== LDAP sync ==" +docker exec "$PHP_C" php /crons/ldap-sync.php || true + +echo "== Mailbox check (expect active=0) ==" +MB=$(mysql_q "SELECT username, active, authsource FROM mailbox WHERE username='${EMAIL}';") +echo "$MB" +if echo "$MB" | grep -qP '\t1\t'; then + echo "WARN: mailbox still active — deactivate in Mailcow Admin first (Path B)" +fi + +echo "== Transport map ==" +CNT=$(mysql_q "SELECT COUNT(*) FROM transports WHERE destination='${EMAIL}';") +if [ "${CNT}" = "0" ]; then + mysql_exec " + INSERT INTO transports (destination, nexthop, username, password, is_mx_based, active) + SELECT '${EMAIL}', '${NEXTHOP}', r.username, r.password, 0, 1 + FROM relayhosts r + WHERE r.id=${RELAYHOST_ID} AND r.active=1 + LIMIT 1; + " + echo "Inserted transport for ${EMAIL} -> ${NEXTHOP}" +else + mysql_exec " + UPDATE transports t + JOIN relayhosts r ON r.id=${RELAYHOST_ID} AND r.active=1 + SET t.nexthop='${NEXTHOP}', t.username=r.username, t.password=r.password, t.active=1 + WHERE t.destination='${EMAIL}'; + " + echo "Updated existing transport for ${EMAIL}" +fi + +mysql_exec "SELECT id, destination, nexthop, username, is_mx_based, active FROM transports WHERE destination='${EMAIL}';" + +echo "== Alias (SOGo RCPT acceptance) ==" +ALIAS=$(mysql_q "SELECT COUNT(*) FROM alias WHERE address='${EMAIL}';") +if [ "${ALIAS}" != "0" ]; then + mysql_exec "UPDATE alias SET active=1 WHERE address='${EMAIL}';" + mysql_exec "SELECT address, goto, active FROM alias WHERE address='${EMAIL}';" +else + echo "No alias row for ${EMAIL} (OK if sending only via postfix, not SOGo)" +fi + +echo "== Postfix lookup ==" +docker exec "$POSTFIX_C" postmap -q "${EMAIL}" mysql:/opt/postfix/conf/sql/mysql_transport_maps.cf || true + +echo "== Reload postfix ==" +docker exec "$POSTFIX_C" postfix reload + +echo "" +echo "DONE. Test: send from support@ to ${EMAIL}, verify inbox on cPanel." +echo "Admin UI: Configuration -> Routing -> Transport maps" diff --git a/Mailcow/scripts/switch-support-to-ldap.sh b/Mailcow/scripts/switch-support-to-ldap.sh new file mode 100644 index 0000000..cb80d69 --- /dev/null +++ b/Mailcow/scripts/switch-support-to-ldap.sh @@ -0,0 +1,49 @@ +#!/bin/bash +# Switch support@geonet.co.id from authsource mailcow → ldap +# Inbox/fetchmail unchanged — only IMAP/SMTP login uses AD password +set -euo pipefail + +MAILBOX='support@geonet.co.id' +STACK='/opt/stacks/mailcow' +MYSQL_C='mailcowdockerized-mysql-mailcow-1' +DOVECOT_C='mailcowdockerized-dovecot-mailcow-1' +SOGO_C='mailcowdockerized-sogo-mailcow-1' +PHP_C='mailcowdockerized-php-fpm-mailcow-1' + +mysql_q() { + docker exec "$MYSQL_C" bash -lc "mysql mailcow -uroot -p\"\$MYSQL_ROOT_PASSWORD\" -N -e \"$1\"" +} + +echo "== Pre-check ==" +BEFORE=$(mysql_q "SELECT username, active, authsource FROM mailbox WHERE username='${MAILBOX}';") +echo "Mailbox: $BEFORE" +if ! echo "$BEFORE" | grep -q "$MAILBOX"; then + echo "ERROR: mailbox ${MAILBOX} not found" + exit 1 +fi + +echo "== LDAP sync (import/provision) ==" +docker exec "$PHP_C" php /crons/ldap-sync.php || true + +echo "== Switch authsource to ldap ==" +mysql_q "UPDATE mailbox SET authsource='ldap' WHERE username='${MAILBOX}';" +AFTER=$(mysql_q "SELECT username, active, authsource FROM mailbox WHERE username='${MAILBOX}';") +echo "Mailbox after: $AFTER" + +echo "== SOGo static view (LDAP user) ==" +# LDAP users: clear local password hash in SOGo view; SOGo authenticates via LDAP +docker exec "$MYSQL_C" bash -lc "mysql mailcow -uroot -p\"\$MYSQL_ROOT_PASSWORD\" -e \" +UPDATE _sogo_static_view SET c_password = NULL WHERE c_name = '${MAILBOX}'; +\"" || echo "WARN: _sogo_static_view update skipped (table/row may differ)" + +echo "== Restart mail services ==" +cd "$STACK" +docker compose restart dovecot-mailcow sogo-mailcow + +echo "== fetchmail timer ==" +systemctl is-active fetchmail-support.timer +docker exec "$DOVECOT_C" doveadm mailbox status -u "$MAILBOX" messages INBOX 2>/dev/null || true + +echo "" +echo "DONE. Test IMAP with AD password for ${MAILBOX}" +echo "fetchmail POP3 drain unchanged (cPanel -> same inbox)" diff --git a/Mailcow/scripts/sync-ssl-from-nginx.sh b/Mailcow/scripts/sync-ssl-from-nginx.sh new file mode 100644 index 0000000..703c121 --- /dev/null +++ b/Mailcow/scripts/sync-ssl-from-nginx.sh @@ -0,0 +1,18 @@ +#!/bin/bash +# Sync Let's Encrypt cert from nginx (.24) to Mailcow SMTP/IMAP (.28) +# Run from workstation with SSH to both hosts, or schedule after certbot renew on .24 +set -euo pipefail + +NGINX_HOST="${NGINX_HOST:-10.100.1.24}" +MAILCOW_HOST="${MAILCOW_HOST:-10.100.1.28}" +DOMAIN="${DOMAIN:-sync.geonet.co.id}" +STACK="/opt/stacks/mailcow" +CERT_SRC="/etc/letsencrypt/live/${DOMAIN}/fullchain.pem" +KEY_SRC="/etc/letsencrypt/live/${DOMAIN}/privkey.pem" + +echo "Copy LE cert ${DOMAIN} -> Mailcow ${MAILCOW_HOST}" +ssh root@"${NGINX_HOST}" "cat ${CERT_SRC}" | ssh root@"${MAILCOW_HOST}" "cat > ${STACK}/data/assets/ssl/cert.pem" +ssh root@"${NGINX_HOST}" "cat ${KEY_SRC}" | ssh root@"${MAILCOW_HOST}" "cat > ${STACK}/data/assets/ssl/key.pem" +ssh root@"${MAILCOW_HOST}" "chmod 600 ${STACK}/data/assets/ssl/key.pem && openssl x509 -in ${STACK}/data/assets/ssl/cert.pem -noout -issuer" +ssh root@"${MAILCOW_HOST}" "cd ${STACK} && docker compose restart postfix-mailcow dovecot-mailcow nginx-mailcow" +echo "DONE" diff --git a/Mikrotik/.env.example b/Mikrotik/.env.example new file mode 100644 index 0000000..d04da62 --- /dev/null +++ b/Mikrotik/.env.example @@ -0,0 +1,20 @@ +# MikroTik — template (AMAN di-commit) +# Credential SSH: key ~/.ssh/id_rsa_mikrotik — bukan di file ini + +MIKROTIK_HOST=10.100.1.1 +MIKROTIK_HOST_OFFICE=192.168.0.1 +MIKROTIK_SSH_PORT=255 +MIKROTIK_SSH_USER=admin +MIKROTIK_SSH_MAC=hmac-sha1 + +# WAN publik (blok ISP) +WAN_PUBLIC_BLOCK=117.102.73.96/29 +WAN_GATEWAY_ISP1=117.102.73.97 +WAN_IP_PRIMARY=117.102.73.102 + +# Segment internal +LAN_SERVER=10.100.1.0/24 +LAN_OFFICE=192.168.0.0/24 +LAN_VPN=100.100.1.0/24 + +# Dokumentasi: docs/server.md, docs/system-requirements.md diff --git a/Mikrotik/.gitignore b/Mikrotik/.gitignore new file mode 100644 index 0000000..649a63f --- /dev/null +++ b/Mikrotik/.gitignore @@ -0,0 +1,7 @@ +# Local secrets — never commit +.env +.env.* +!.env.example + +# Optional: full export with show-sensitive (if ever used) +backups/*-sensitive.rsc diff --git a/Mikrotik/AGENTS.md b/Mikrotik/AGENTS.md new file mode 100644 index 0000000..a6cc52f --- /dev/null +++ b/Mikrotik/AGENTS.md @@ -0,0 +1,36 @@ +# AGENTS.md — Cold Start + +> Project: `Mikrotik/` +> Sesi: [docs/ai-session-summary.md](./docs/ai-session-summary.md) +> Peta: [docs/context-index.md](./docs/context-index.md) +> Env: [.env.example](./.env.example) + +## Apa ini? + +Gateway perimeter GeoNet — MikroTik CCR2004 (`10.100.1.1`), NAT publik, dual-WAN hybrid failover, VPN, split-DNS. SSOT config backup & arsitektur. + +## Aturan kritis + +- SSH: **port 255**, `-m hmac-sha1`, key `~/.ssh/id_rsa_mikrotik` (lihat `server-connection/scripts/ssh-mikrotik.ps1`) +- **Jangan** commit password / `export show-sensitive` — redaksi `nasFtpPass` di backup `.rsc` +- Ubah routing/NAT hanya setelah backup + catat di `docs/version.md` +- DNS publik domain (SPF/DKIM) **bukan** di MikroTik — di registrar +- No commit kecuali user minta +- SSH oleh agent wajib persetujuan user + +## Lanjut kerja + +``` +1. AGENTS.md → docs/ai-session-summary.md → STOP +2. docs/architecture/system-overview.md, docs/server.md, backups/ +``` + +## Pointer + +| Butuh | Buka | +|-------|------| +| Arsitektur | [docs/architecture/system-overview.md](./docs/architecture/system-overview.md) | +| NAT mail `.28` | [docs/notes/nat-mail-gisportal.md](./docs/notes/nat-mail-gisportal.md) | +| Restore | [backups/README.md](./backups/README.md) | +| Script deploy | `server-connection/scripts/apply-failover-mikrotik.ps1` | +| Legacy audit | `server-connection/server/mikrotik-audit.txt` | diff --git a/Mikrotik/README.md b/Mikrotik/README.md new file mode 100644 index 0000000..d0da7ad --- /dev/null +++ b/Mikrotik/README.md @@ -0,0 +1,12 @@ +# MikroTik — Gateway GeoNet + +Router perimeter: NAT, dual-WAN hybrid, VPN, split-DNS. + +| Item | Nilai | +|------|-------| +| Model | CCR2004-1G-12S+2XS | +| RouterOS | 7.5 | +| SSH | `admin@10.100.1.1:255` + `-m hmac-sha1` | +| Backup repo | `backups/mikrotik-export-*.rsc` | + +**AI entry point:** [`docs/context-index.md`](docs/context-index.md) diff --git a/Mikrotik/backups/README.md b/Mikrotik/backups/README.md new file mode 100644 index 0000000..765403e --- /dev/null +++ b/Mikrotik/backups/README.md @@ -0,0 +1,34 @@ +# MikroTik Config Backups + +> **Jangan** commit file yang berisi `password=` / `show-sensitive`. + +## File + +| File | Tanggal | Keterangan | +|------|---------|------------| +| `mikrotik-export-2026-07-06.rsc` | 2026-07-06 | `/export compact` live dari `10.100.1.1` — password NAS script **diredaksi** | + +Backup harian otomatis juga ke QNAP: `mainpve/mikrotik/nas-latest.*` (scheduler `nas-backup-daily`). + +## Restore (uji di maintenance window) + +```bash +# Via SSH (port 255) +ssh -m hmac-sha1 -i ~/.ssh/id_rsa_mikrotik admin@10.100.1.1 -p 255 + +# Upload .rsc ke router lalu: +/import file-name=mikrotik-export-2026-07-06.rsc +``` + +Atau Winbox → Files → upload → Import. + +**Peringatan:** import penuh bisa menimpa konfigurasi live. Untuk restore parsial, edit `.rsc` atau gunakan `/system backup load` dari file `.backup` di NAS. + +## Regenerate backup ke repo + +```powershell +cd server-connection +.\scripts\ssh-mikrotik.ps1 -Command "/export compact" +# Salin output ke Mikrotik/backups/mikrotik-export-YYYY-MM-DD.rsc +# Redaksi nasFtpPass sebelum commit +``` diff --git a/Mikrotik/backups/mikrotik-export-2026-07-06.rsc b/Mikrotik/backups/mikrotik-export-2026-07-06.rsc new file mode 100644 index 0000000..b5ed17a --- /dev/null +++ b/Mikrotik/backups/mikrotik-export-2026-07-06.rsc @@ -0,0 +1,635 @@ +# jul/06/2026 15:46:32 by RouterOS 7.5 +# software id = E3H0-EVXR +# +# model = CCR2004-1G-12S+2XS +# serial number = HDD08647CP6 +/interface bridge +add name=office +add name=server +add add-dhcp-option82=yes dhcp-snooping=yes name=vpn +/interface ethernet +set [ find default-name=ether1 ] comment="ISP BIZNET" +set [ find default-name=sfp-sfpplus1 ] auto-negotiation=no comment=\ + "ISP IDBIZ" +set [ find default-name=sfp-sfpplus2 ] comment=DELL-main-netwokrkVMBR0 \ + loop-protect=on loop-protect-disable-time=10s +set [ find default-name=sfp-sfpplus3 ] comment=DELL loop-protect=on \ + loop-protect-disable-time=10s +set [ find default-name=sfp-sfpplus4 ] comment=IBM loop-protect=on \ + loop-protect-disable-time=10s +set [ find default-name=sfp-sfpplus5 ] comment=NAS +set [ find default-name=sfp-sfpplus6 ] auto-negotiation=no disabled=yes +set [ find default-name=sfp-sfpplus10 ] comment="swich server" +set [ find default-name=sfp-sfpplus11 ] comment="swich production" speed=\ + 10Gbps +set [ find default-name=sfp-sfpplus12 ] comment="swich adm" speed=10Gbps +/interface vlan +add interface=sfp-sfpplus12 loop-protect=on name=vlan3 vlan-id=3 +add interface=sfp-sfpplus10 loop-protect=on name=vlan10 vlan-id=10 +add interface=sfp-sfpplus11 loop-protect=on name=vlan11 vlan-id=11 +add interface=sfp-sfpplus12 loop-protect=on name=vlan12 vlan-id=12 +add interface=sfp-sfpplus10 name=vlan99 vlan-id=99 +add disabled=yes interface=sfp-sfpplus10 loop-protect=on name=vlan2001 \ + vlan-id=2001 +add interface=sfp-sfpplus4 name=vlan2004 vlan-id=2001 +add interface=sfp-sfpplus10 loop-protect=on name=vlan2010 vlan-id=2010 +add interface=sfp-sfpplus12 loop-protect=on name=vlan2012 vlan-id=2012 +/interface wireless security-profiles +set [ find default=yes ] supplicant-identity=MikroTik +/ip pool +add name=dhcp_pool0 ranges=192.168.0.2-192.168.0.254 +add name=dhcp_pool1 ranges=192.168.0.2-192.168.0.254 +add name=dhcp_pool2 ranges=192.168.0.2-192.168.0.254 +add name=dhcp_pool3 ranges=192.168.0.2-192.168.0.254 +add name=dhcp_pool4 ranges=100.100.1.2-100.100.1.254 +add name=dhcp_pool5 ranges=192.168.2.2-192.168.2.254 +add name=dhcp_pool6 ranges=192.168.2.2-192.168.2.254 +/ip dhcp-server +add address-pool=dhcp_pool3 interface=office lease-time=4w3d name=dhcp1 +add address-pool=dhcp_pool4 interface=vpn name=dhcp2 +# DHCP server can not run on slave interface! +add address-pool=dhcp_pool6 interface=vlan2004 name=dhcp3 relay=192.168.2.1 +/port +set 0 name=serial0 +set 1 name=serial1 +/queue simple +add name=multimedia priority=1/1 target=192.168.0.4/32 +add disabled=yes name=priotiry priority=2/2 target=office +/routing table +add disabled=no fib name="KE ISP 1" +add disabled=no fib name="KE ISP 2" +/snmp community +set [ find default=yes ] write-access=yes +/interface bridge port +add bridge=server interface=sfp-sfpplus2 +add bridge=server interface=sfp-sfpplus3 +add bridge=server interface=sfp-sfpplus4 +add bridge=server interface=sfp-sfpplus5 +add bridge=office interface=sfp-sfpplus10 trusted=yes +add bridge=office interface=sfp-sfpplus11 trusted=yes +add bridge=office disabled=yes interface=sfp-sfpplus12 +add bridge=server interface=vlan10 +add bridge=server interface=vlan11 +add bridge=server interface=vlan12 +add bridge=server interface=vlan99 +add bridge=office interface=vlan2010 trusted=yes +add bridge=server interface=vlan3 +add bridge=office interface=vlan2012 trusted=yes +add bridge=office interface=vlan2004 trusted=yes +add bridge=server interface=sfp-sfpplus6 +/interface pptp-server server +# PPTP connections are considered unsafe, it is suggested to use a more modern VPN protocol instead +set enabled=yes +/interface sstp-server server +set enabled=yes +/ip address +add address=192.168.88.1/24 comment=defconf disabled=yes interface=ether1 \ + network=192.168.88.0 +add address=117.102.73.102/29 comment=gisportal.id interface=ether1 network=\ + 117.102.73.96 +add address=117.102.73.101 comment="Not Set" interface=ether1 network=\ + 117.102.73.101 +add address=117.102.73.100 comment=dev.gisportal.id interface=ether1 network=\ + 117.102.73.100 +add address=117.102.73.98 comment=geonet.co.id interface=ether1 network=\ + 117.102.73.96 +add address=10.100.1.1/24 interface=server network=10.100.1.0 +add address=117.102.73.99 comment=geonet.co.id interface=ether1 network=\ + 117.102.73.99 +add address=192.168.0.1/24 interface=sfp-sfpplus10 network=192.168.0.0 +add address=100.100.1.0 interface=vpn network=100.100.1.0 +add address=192.168.2.0/24 interface=vlan2004 network=192.168.2.0 +/ip dhcp-client +add add-default-route=no interface=sfp-sfpplus1 use-peer-dns=no +/ip dhcp-server lease +add address=192.168.0.11 client-id=1:bc:fc:e7:8e:55:67 mac-address=\ + BC:FC:E7:8E:55:67 server=dhcp1 +add address=192.168.0.102 client-id=1:18:fb:7b:a5:50:8b mac-address=\ + 18:FB:7B:A5:50:8B server=dhcp1 +add address=192.168.0.9 client-id=1:18:fd:74:52:8e:5f comment=swich \ + mac-address=18:FD:74:52:8E:5F server=dhcp1 +add address=192.168.0.8 client-id=1:18:fd:74:8b:b2:7f comment=swich \ + mac-address=18:FD:74:8B:B2:7F server=dhcp1 +add address=192.168.0.4 mac-address=10:5F:02:84:F0:2F server=dhcp1 +add address=192.168.0.10 client-id=1:24:5e:be:42:8f:a5 mac-address=\ + 24:5E:BE:42:8F:A5 server=dhcp1 +add address=192.168.0.74 client-id=1:b4:2e:99:2a:30:4c mac-address=\ + B4:2E:99:2A:30:4C server=dhcp1 +add address=192.168.0.20 client-id=1:80:3f:5d:f9:c1:40 comment=WAVLINK \ + mac-address=80:3F:5D:F9:C1:40 server=dhcp1 +add address=192.168.0.57 client-id=1:bc:24:11:5d:58:56 mac-address=\ + BC:24:11:5D:58:56 server=dhcp1 +add address=192.168.0.13 client-id=1:a0:d3:65:73:c7:97 mac-address=\ + A0:D3:65:73:C7:97 server=dhcp1 +add address=192.168.0.18 client-id=1:10:ff:e0:3a:7d:15 mac-address=\ + 10:FF:E0:3A:7D:15 server=dhcp1 +add address=192.168.0.64 client-id=1:72:7e:64:31:eb:13 mac-address=\ + 72:7E:64:31:EB:13 server=dhcp1 +add address=192.168.0.80 client-id=1:0:1:f5:2:b:d1 mac-address=\ + 00:01:F5:02:0B:D1 server=dhcp1 +add address=192.168.0.69 mac-address=40:A3:CC:B1:02:15 server=dhcp1 +/ip dhcp-server network +add address=100.100.1.0/24 dns-server=100.100.1.1 gateway=100.100.1.1 +add address=192.168.0.0/24 dns-server=203.142.82.222,203.142.84.222 gateway=\ + 192.168.0.1 +add address=192.168.2.0/24 dns-server=8.8.8.8,8.8.1.1 gateway=192.168.2.1 +/ip dns +set allow-remote-requests=yes servers=203.142.82.222,203.142.84.222 +/ip dns static +add address=10.100.1.61 disabled=yes name=arcgisenterprise.gisportal.id +add address=10.100.1.72 name=aernd.gisportal.id +add address=10.100.1.25 name=database.gisportal.id +add address=10.100.1.24 comment="split-dns gisportal apex" name=gisportal.id +add address=10.100.1.24 comment="split-dns dockge" name=dockge.gisportal.id +add address=10.100.1.24 name=geonet.gisportal.id +add address=10.100.1.24 name=api.gisportal.id +add address=10.100.1.25 comment="split-dns database regexp" regexp=\ + "^database\\.gisportal\\.id" +add address=10.100.1.72 comment="split-dns aernd regexp" regexp=\ + "^aernd\\.gisportal\\.id" +add address=10.100.1.51 comment="split-dns dev regexp" regexp=\ + "^dev\\.gisportal\\.id" +add address=10.100.1.24 comment="split-dns gisportal catch-all" regexp=\ + "\\.gisportal\\.id" +add address=10.100.1.24 comment="split-dns iguf" name=iguf.geonet.co.id +add address=10.100.1.24 comment=geonetagent-collector name=\ + collector.gisportal.id +add address=10.100.1.24 comment=geonetagent-agent name=agent.gisportal.id +/ip firewall address-list +add address=10.100.1.101 list=blocked-internet +add address=10.100.1.100 list=blocked-internet +add address=10.100.1.88 list=blocked-internet +add address=10.100.1.84 list=blocked-internet +add address=10.100.1.91 list=blocked-internet +add address=10.100.1.61 list=blocked-internet +add address=10.100.1.72 list=blocked-internet +add address=10.100.1.80 list=blocked-internet +add address=10.100.1.40 list=blocked-internet +add address=10.100.1.51 list=blocked-internet +add address=10.100.1.25 list=blocked-internet +add address=10.100.1.56 list=blocked-internet +add address=10.100.1.58 list=blocked-internet +add address=10.100.1.55 list=blocked-internet +add address=10.100.1.53 list=blocked-internet +/ip firewall filter +add action=drop chain=forward connection-state=new dst-address-list=ddosed \ + src-address-list=ddoser +add action=jump chain=forward connection-state=new jump-target=detect-ddos +add action=return chain=detect-ddos dst-limit=32,32,src-and-dst-addresses/1s +add action=add-dst-to-address-list address-list=ddosed address-list-timeout=\ + 10m chain=detect-ddos +add action=add-src-to-address-list address-list=ddoser address-list-timeout=\ + 10m chain=detect-ddos +add action=drop chain=forward comment=block-internet-biznet disabled=yes \ + out-interface=ether1 src-address-list=blocked-internet +add action=drop chain=forward comment=block-internet-idbiz disabled=yes \ + out-interface=sfp-sfpplus1 src-address-list=blocked-internet +/ip firewall mangle +add action=accept chain=prerouting comment="hybrid server-local-bypass" \ + dst-address=10.100.1.0/24 src-address=10.100.1.0/24 +add action=accept chain=prerouting comment="hybrid server-to-office-bypass" \ + dst-address=192.168.0.0/24 src-address=10.100.1.0/24 +add action=accept chain=prerouting comment="hybrid server-to-vpn-bypass" \ + dst-address=100.100.1.0/24 src-address=10.100.1.0/24 +add action=accept chain=prerouting comment="hybrid mgmt bypass laptop" \ + disabled=yes src-address=192.168.0.33 +add action=accept chain=prerouting comment="hybrid mgmt bypass laptop" \ + src-address=10.100.1.220 +add action=accept chain=prerouting comment="hybrid server hairpin bypass" \ + dst-address=117.102.73.96/29 src-address=10.100.1.0/24 +add action=mark-routing chain=prerouting comment=temp-speedtest-isp2 \ + disabled=yes new-routing-mark="KE ISP 2" passthrough=yes src-address=\ + 10.100.1.24 +add action=mark-routing chain=prerouting comment="hybrid server force ISP1" \ + new-routing-mark="KE ISP 1" passthrough=no src-address=10.100.1.0/24 +add action=mark-connection chain=prerouting connection-mark=no-mark disabled=\ + yes in-interface=vlan2004 new-connection-mark="ISP 2" passthrough=yes \ + per-connection-classifier=both-addresses-and-ports:2/1 +add action=mark-connection chain=prerouting connection-mark=no-mark disabled=\ + yes in-interface=server new-connection-mark="ISP 1" passthrough=yes \ + per-connection-classifier=both-addresses-and-ports:2/0 +add action=mark-routing chain=prerouting connection-mark="ISP 2" disabled=yes \ + in-interface=vlan2004 new-routing-mark="KE ISP 2" passthrough=yes \ + per-connection-classifier=both-addresses-and-ports:2/1 +add action=mark-connection chain=prerouting connection-mark=no-mark disabled=\ + yes in-interface=sfp-sfpplus1 new-connection-mark="ISP 2" passthrough=yes +add action=mark-connection chain=prerouting connection-mark=no-mark disabled=\ + yes in-interface=ether1 new-connection-mark="ISP 1" passthrough=yes +add action=mark-routing chain=output connection-mark="ISP 2" disabled=yes \ + new-routing-mark="KE ISP 2" passthrough=yes +add action=accept chain=prerouting comment="hybrid office-to-server-bypass" \ + dst-address=10.100.1.0/24 in-interface=office +add action=accept chain=prerouting comment="hybrid office hairpin bypass" \ + dst-address=117.102.73.96/29 in-interface=office +add action=mark-connection chain=prerouting comment="hybrid office PCC ISP1" \ + connection-mark=no-mark in-interface=office new-connection-mark="ISP 1" \ + passthrough=yes per-connection-classifier=both-addresses-and-ports:2/0 +add action=mark-connection chain=prerouting comment="hybrid office PCC ISP2" \ + connection-mark=no-mark in-interface=office new-connection-mark="ISP 2" \ + passthrough=yes per-connection-classifier=both-addresses-and-ports:2/1 +add action=accept chain=prerouting comment="hybrid vpn hairpin bypass" \ + dst-address=117.102.73.96/29 src-address=100.100.1.0/24 +add action=mark-connection chain=prerouting comment="hybrid vpn PCC ISP1" \ + connection-mark=no-mark disabled=yes in-interface=vpn \ + new-connection-mark="ISP 1" passthrough=yes per-connection-classifier=\ + both-addresses-and-ports:2/0 +add action=mark-connection chain=prerouting comment="hybrid vpn PCC ISP2" \ + connection-mark=no-mark disabled=yes in-interface=vpn \ + new-connection-mark="ISP 2" passthrough=yes per-connection-classifier=\ + both-addresses-and-ports:2/1 +add action=mark-routing chain=prerouting comment="hybrid route ISP1" \ + connection-mark="ISP 1" new-routing-mark="KE ISP 1" passthrough=yes +add action=mark-routing chain=prerouting comment="hybrid route ISP2" \ + connection-mark="ISP 2" new-routing-mark="KE ISP 2" passthrough=yes +/ip firewall nat +add action=masquerade chain=srcnat out-interface=ether1 +add action=masquerade chain=srcnat out-interface=sfp-sfpplus1 +add action=masquerade chain=srcnat +add action=dst-nat chain=dstnat dst-address=117.102.73.102 dst-port=80 \ + protocol=tcp to-addresses=10.100.1.24 to-ports=80 +add action=dst-nat chain=dstnat disabled=yes dst-address=117.102.73.101 \ + dst-port=80 protocol=tcp to-addresses=10.100.1.24 to-ports=80 +add action=dst-nat chain=dstnat dst-address=117.102.73.101 dst-port=80 \ + protocol=tcp to-addresses=10.100.1.76 to-ports=80 +add action=dst-nat chain=dstnat dst-address=117.102.73.99 dst-port=25 \ + protocol=tcp to-addresses=10.100.1.76 to-ports=25 +add action=dst-nat chain=dstnat dst-address=117.102.73.101 dst-port=25 \ + protocol=tcp to-addresses=10.100.1.76 to-ports=25 +add action=dst-nat chain=dstnat dst-address=117.102.73.101 dst-port=143 \ + protocol=tcp to-addresses=10.100.1.76 to-ports=143 +add action=dst-nat chain=dstnat dst-address=117.102.73.99 dst-port=143 \ + protocol=tcp to-addresses=10.100.1.76 to-ports=143 +add action=dst-nat chain=dstnat dst-address=117.102.73.101 dst-port=993 \ + protocol=tcp to-addresses=10.100.1.76 to-ports=993 +add action=dst-nat chain=dstnat dst-address=117.102.73.99 dst-port=993 \ + protocol=tcp to-addresses=10.100.1.76 to-ports=993 +add action=dst-nat chain=dstnat dst-address=117.102.73.101 dst-port=587 \ + protocol=tcp to-addresses=10.100.1.76 to-ports=587 +add action=dst-nat chain=dstnat dst-address=117.102.73.99 dst-port=587 \ + protocol=tcp to-addresses=10.100.1.76 to-ports=587 +add action=dst-nat chain=dstnat disabled=yes dst-address=117.102.73.101 \ + dst-port=443 protocol=tcp to-addresses=10.100.1.24 to-ports=443 +add action=dst-nat chain=dstnat dst-address=117.102.73.102 dst-port=24 \ + protocol=tcp to-addresses=10.100.1.24 to-ports=22 +add action=dst-nat chain=dstnat dst-address=117.102.73.102 dst-port=21 \ + protocol=tcp to-addresses=10.100.1.10 to-ports=21 +add action=dst-nat chain=dstnat dst-address=117.102.73.102 dst-port=443 \ + protocol=tcp to-addresses=10.100.1.24 to-ports=443 +add action=dst-nat chain=dstnat dst-address=117.102.73.99 dst-port=443 \ + protocol=tcp to-addresses=10.100.1.24 to-ports=443 +add action=dst-nat chain=dstnat dst-address=117.102.73.99 dst-port=80 \ + protocol=tcp to-addresses=10.100.1.24 to-ports=80 +add action=dst-nat chain=dstnat dst-address=117.102.73.100 dst-port=443 \ + protocol=tcp to-addresses=10.100.1.51 to-ports=443 +add action=dst-nat chain=dstnat dst-address=117.102.73.102 dst-port=1433 \ + protocol=tcp to-addresses=10.100.1.25 to-ports=1433 +add action=dst-nat chain=dstnat comment="rnd SQL Server 2016" dst-address=\ + 117.102.73.102 dst-port=1434 protocol=tcp to-addresses=10.100.1.75 \ + to-ports=1433 +add action=dst-nat chain=dstnat comment="Zabbiz agenet active" dst-address=\ + 117.102.73.102 dst-port=10051 protocol=tcp to-addresses=10.100.1.42 \ + to-ports=10051 +add action=dst-nat chain=dstnat comment="rnd SQL Server 2022" dst-address=\ + 117.102.73.102 dst-port=1437 protocol=tcp to-addresses=10.100.1.77 \ + to-ports=1433 +add action=dst-nat chain=dstnat comment="rnd SQL Server 2016" dst-address=\ + 117.102.73.102 dst-port=1436 protocol=tcp to-addresses=10.100.1.76 \ + to-ports=1433 +add action=dst-nat chain=dstnat dst-address=117.102.73.102 dst-port=5432 \ + protocol=tcp to-addresses=10.100.1.25 to-ports=5432 +add action=dst-nat chain=dstnat dst-address=117.102.73.99 dst-port=8080 \ + protocol=tcp to-addresses=10.100.1.27 to-ports=8080 +add action=dst-nat chain=dstnat dst-address=117.102.73.102 dst-port=5434 \ + protocol=tcp to-addresses=10.100.1.27 to-ports=5434 +add action=dst-nat chain=dstnat dst-address=117.102.73.100 dst-port=30443 \ + protocol=tcp to-addresses=10.100.1.59 to-ports=30443 +add action=dst-nat chain=dstnat dst-address=117.102.73.100 dst-port=6143 \ + protocol=tcp to-addresses=10.100.1.59 to-ports=6143 +add action=dst-nat chain=dstnat dst-address=117.102.73.100 dst-port=13443 \ + protocol=tcp to-addresses=10.100.1.57 to-ports=13443 +add action=dst-nat chain=dstnat dst-address=117.102.73.100 dst-port=6443 \ + protocol=tcp to-addresses=10.100.1.51 to-ports=6443 +add action=dst-nat chain=dstnat dst-address=117.102.73.100 dst-port=80 \ + protocol=tcp to-addresses=10.100.1.51 to-ports=80 +add action=dst-nat chain=dstnat dst-address=117.102.73.100 dst-port=7443 \ + protocol=tcp to-addresses=10.100.1.51 to-ports=7443 +add action=dst-nat chain=dstnat dst-address=117.102.73.100 dst-port=2443 \ + protocol=tcp to-addresses=10.100.1.51 to-ports=2443 +add action=dst-nat chain=dstnat dst-address=117.102.73.102 dst-port=5433 \ + protocol=tcp to-addresses=10.100.1.27 to-ports=5432 +add action=dst-nat chain=dstnat dst-address=117.102.73.102 dst-port=25 \ + protocol=tcp to-addresses=10.100.1.28 to-ports=25 +add action=dst-nat chain=dstnat dst-address=117.102.73.102 dst-port=993 \ + protocol=tcp to-addresses=10.100.1.28 to-ports=993 +add action=dst-nat chain=dstnat dst-address=117.102.73.102 dst-port=587 \ + protocol=tcp to-addresses=10.100.1.28 to-ports=587 +add action=dst-nat chain=dstnat dst-address=117.102.73.102 dst-port=465 \ + protocol=tcp to-addresses=10.100.1.28 to-ports=465 +add action=dst-nat chain=dstnat comment=geonet.co.id disabled=yes \ + dst-address=117.102.73.99 dst-port=25 protocol=tcp to-addresses=\ + 10.100.1.40 to-ports=25 +add action=dst-nat chain=dstnat dst-address=117.102.73.102 dst-port=995 \ + protocol=tcp to-addresses=10.100.1.40 to-ports=995 +add action=dst-nat chain=dstnat comment=geonet.co.id disabled=yes \ + dst-address=117.102.73.99 dst-port=995 protocol=tcp to-addresses=\ + 10.100.1.40 to-ports=995 +add action=dst-nat chain=dstnat disabled=yes dst-address=117.102.73.102 \ + dst-port=25 protocol=udp to-addresses=10.100.1.40 to-ports=25 +add action=dst-nat chain=dstnat dst-address=117.102.73.102 dst-port=587 \ + protocol=tcp to-addresses=10.100.1.40 to-ports=587 +add action=dst-nat chain=dstnat comment=geonet.co.id disabled=yes \ + dst-address=117.102.73.99 dst-port=587 protocol=tcp to-addresses=\ + 10.100.1.40 to-ports=587 +add action=dst-nat chain=dstnat disabled=yes dst-address=117.102.73.102 \ + dst-port=587 protocol=udp to-addresses=10.100.1.40 to-ports=587 +add action=dst-nat chain=dstnat dst-address=117.102.73.102 dst-port=389 \ + protocol=tcp to-addresses=10.100.1.40 to-ports=389 +add action=dst-nat chain=dstnat comment=geonet.co.id disabled=yes \ + dst-address=117.102.73.99 dst-port=389 protocol=tcp to-addresses=\ + 10.100.1.40 to-ports=389 +add action=dst-nat chain=dstnat disabled=yes dst-address=117.102.73.102 \ + dst-port=389 protocol=udp to-addresses=10.100.1.40 to-ports=389 +add action=dst-nat chain=dstnat disabled=yes dst-address=117.102.73.102 \ + dst-port=143 protocol=udp to-addresses=10.100.1.40 to-ports=143 +add action=dst-nat chain=dstnat dst-address=117.102.73.102 dst-port=143 \ + protocol=tcp to-addresses=10.100.1.40 to-ports=143 +add action=dst-nat chain=dstnat comment=geonet.co.id disabled=yes \ + dst-address=117.102.73.99 dst-port=143 protocol=tcp to-addresses=\ + 10.100.1.40 to-ports=143 +add action=dst-nat chain=dstnat disabled=yes dst-address=117.102.73.102 \ + dst-port=110 protocol=udp to-addresses=10.100.1.40 to-ports=110 +add action=dst-nat chain=dstnat dst-address=117.102.73.102 dst-port=110 \ + protocol=tcp to-addresses=10.100.1.40 to-ports=110 +add action=dst-nat chain=dstnat comment=geonet.co.id disabled=yes \ + dst-address=117.102.73.99 dst-port=110 protocol=tcp to-addresses=\ + 10.100.1.40 to-ports=110 +add action=masquerade chain=srcnat comment="Hairpin NAT" dst-address=\ + 10.100.1.24 dst-port=443 out-interface=ether1 protocol=tcp src-address=\ + 192.168.0.0/24 +add action=masquerade chain=srcnat comment="Hairpin NAT" dst-address=\ + 10.100.1.100 dst-port=443 out-interface=ether1 protocol=tcp src-address=\ + 192.168.0.0/24 +add action=masquerade chain=srcnat comment="Hairpin NAT" dst-address=\ + 10.100.1.24 dst-port=80 out-interface=ether1 protocol=tcp src-address=\ + 192.168.0.0/24 +add action=dst-nat chain=dstnat dst-address=117.102.73.101 dst-port=995 \ + protocol=tcp to-addresses=10.100.1.76 to-ports=995 +add action=dst-nat chain=dstnat dst-address=117.102.73.99 dst-port=995 \ + protocol=tcp to-addresses=10.100.1.76 to-ports=995 +add action=dst-nat chain=dstnat dst-address=117.102.73.101 dst-port=465 \ + protocol=tcp to-addresses=10.100.1.76 to-ports=465 +add action=dst-nat chain=dstnat dst-address=117.102.73.99 dst-port=465 \ + protocol=tcp to-addresses=10.100.1.76 to-ports=465 +add action=dst-nat chain=dstnat dst-address=117.102.73.99 dst-port=993 \ + protocol=tcp to-addresses=10.100.1.76 to-ports=993 +add action=masquerade chain=srcnat comment=hairpin-10.100.1-nginx-443 \ + dst-address=10.100.1.24 dst-port=443 protocol=tcp src-address=\ + 10.100.1.0/24 +add action=masquerade chain=srcnat comment=hairpin-10.100.1-nginx-80 \ + dst-address=10.100.1.24 dst-port=80 protocol=tcp src-address=\ + 10.100.1.0/24 +add action=masquerade chain=srcnat comment=hairpin-vpn-nginx-443 dst-address=\ + 10.100.1.24 dst-port=443 protocol=tcp src-address=100.100.1.0/24 +add action=masquerade chain=srcnat comment=hairpin-vpn-nginx-80 dst-address=\ + 10.100.1.24 dst-port=80 protocol=tcp src-address=100.100.1.0/24 +add action=dst-nat chain=dstnat comment=ssh-mikrotik-public-102 dst-address=\ + 117.102.73.102 dst-port=255 protocol=tcp to-addresses=10.100.1.1 \ + to-ports=255 +add action=dst-nat chain=dstnat comment=ssh-nginx-public-22 disabled=yes \ + dst-address=117.102.73.102 dst-port=22 protocol=tcp to-addresses=\ + 10.100.1.24 to-ports=22 +add action=masquerade chain=srcnat comment=hairpin-ssh-mikrotik dst-address=\ + 10.100.1.1 dst-port=255 protocol=tcp src-address=10.100.1.0/24 +add action=masquerade chain=srcnat comment=hairpin-ssh-nginx disabled=yes \ + dst-address=10.100.1.24 dst-port=22 protocol=tcp src-address=\ + 10.100.1.0/24 +add action=masquerade chain=srcnat comment=hairpin-ssh-mikrotik-office \ + dst-address=10.100.1.1 dst-port=255 protocol=tcp src-address=\ + 192.168.0.0/24 +add action=masquerade chain=srcnat comment=hairpin-ssh-nginx-office disabled=\ + yes dst-address=10.100.1.24 dst-port=22 protocol=tcp src-address=\ + 192.168.0.0/24 +add action=dst-nat chain=dstnat comment=ssh-public-db dst-address=\ + 117.102.73.102 dst-port=225 protocol=tcp to-addresses=10.100.1.25 \ + to-ports=22 +add action=masquerade chain=srcnat comment=hairpin-ssh-public-db dst-address=\ + 10.100.1.25 dst-port=22 protocol=tcp src-address=10.100.1.0/24 +add action=masquerade chain=srcnat comment=hairpin-ssh-public-db-office \ + dst-address=10.100.1.25 dst-port=22 protocol=tcp src-address=\ + 192.168.0.0/24 +/ip route +add check-gateway=ping comment="hybrid failover ISP1 primary" disabled=no \ + distance=1 dst-address=0.0.0.0/0 gateway=117.102.73.97 pref-src="" \ + routing-table=main scope=30 suppress-hw-offload=no target-scope=10 +add check-gateway=none comment="hybrid ISP2" disabled=no distance=1 \ + dst-address=0.0.0.0/0 gateway=192.168.1.1 pref-src="" routing-table=\ + "KE ISP 2" scope=30 suppress-hw-offload=no target-scope=10 +add check-gateway=ping comment="hybrid failover ISP2 backup" disabled=no \ + distance=2 dst-address=0.0.0.0/0 gateway=192.168.1.1 routing-table=main +add check-gateway=none comment="hybrid ISP1" disabled=no distance=1 \ + dst-address=0.0.0.0/0 gateway=117.102.73.97 routing-table="KE ISP 1" +add comment="hybrid ISP1 WAN lan" distance=1 dst-address=117.102.73.96/29 \ + gateway=ether1 routing-table="KE ISP 1" +add comment="hybrid ISP2 WAN lan" distance=1 dst-address=192.168.1.0/24 \ + gateway=sfp-sfpplus1 routing-table="KE ISP 2" +add comment="hybrid office lan ISP1" distance=1 dst-address=192.168.0.0/24 \ + gateway=office routing-table="KE ISP 1" +add comment="hybrid office lan ISP2" distance=1 dst-address=192.168.0.0/24 \ + gateway=office routing-table="KE ISP 2" +/ip service +set telnet disabled=yes +set ftp disabled=yes +set www disabled=yes +set ssh port=255 +set api disabled=yes +set winbox address=10.100.1.0/24,192.168.0.0/24 +set api-ssl disabled=yes +/ppp aaa +set use-radius=yes +/ppp secret +add local-address=10.100.1.1 name=rbsetiawan remote-address=10.100.1.220 +add local-address=10.100.1.1 name=asobari remote-address=10.100.1.225 +add local-address=10.100.1.1 name=uabdurrohman remote-address=10.100.1.226 +add local-address=10.100.1.1 name=trachman remote-address=10.100.1.227 +add local-address=10.100.1.1 name=test remote-address=10.100.1.211 +add local-address=10.100.1.1 name=dpradana remote-address=10.100.1.228 +add local-address=10.100.1.1 name=ataufik remote-address=10.100.1.229 +add local-address=10.100.1.1 name=awrahajeng remote-address=10.100.1.230 +/radius +add address=10.100.1.40 domain=gisportal.id service=ppp src-address=\ + 10.100.1.1 +/routing rule +add action=lookup comment="hybrid ISP1" routing-mark="KE ISP 1" table=\ + "KE ISP 1" +add action=lookup comment="hybrid ISP2" routing-mark="KE ISP 2" table=\ + "KE ISP 2" +/snmp +set enabled=yes +/system clock +set time-zone-name=Asia/Jakarta +/system scheduler +add comment="hybrid scheduler" interval=1m name=hybrid-sync-mode on-event=\ + hybrid-sync-mode policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon \ + start-date=jun/13/2026 start-time=17:41:40 +add comment="Monitor latency ISP1 vs ISP2" interval=2m name=latency-monitor \ + on-event=latency-monitor policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon \ + start-time=startup +add comment="Backup config ke QNAP 10.100.1.10" interval=1d name=\ + nas-backup-daily on-event=nas-backup policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon \ + start-date=jun/15/2026 start-time=03:00:00 +/system script +add dont-require-permissions=yes name=hybrid-set-mode-both-up owner=admin \ + policy=read,write,test source="\r\ + \n/ip firewall mangle enable [find comment=\"hybrid office PCC ISP1\"]\r\ + \n/ip firewall mangle enable [find comment=\"hybrid office PCC ISP2\"]\r\ + \n/ip firewall mangle disable [find comment=\"hybrid vpn PCC ISP1\"]\r\ + \n/ip firewall mangle disable [find comment=\"hybrid vpn PCC ISP2\"]\r\ + \n/ip firewall mangle enable [find comment=\"hybrid route ISP1\"]\r\ + \n/ip firewall mangle enable [find comment=\"hybrid route ISP2\"]\r\ + \n:log info \"HYBRID: mode BOTH-UP (office PCC 50/50, VPN failover only)\"\ + \r\ + \n" +add dont-require-permissions=yes name=hybrid-set-mode-isp1-down owner=admin \ + policy=read,write,test source="\r\ + \n/ip firewall mangle disable [find comment=\"hybrid office PCC ISP1\"]\r\ + \n/ip firewall mangle disable [find comment=\"hybrid office PCC ISP2\"]\r\ + \n/ip firewall mangle disable [find comment=\"hybrid vpn PCC ISP1\"]\r\ + \n/ip firewall mangle disable [find comment=\"hybrid vpn PCC ISP2\"]\r\ + \n/ip firewall mangle disable [find comment=\"hybrid route ISP1\"]\r\ + \n/ip firewall mangle disable [find comment=\"hybrid route ISP2\"]\r\ + \n:log info \"HYBRID: mode ISP1-DOWN\"\r\ + \n" +add dont-require-permissions=yes name=hybrid-set-mode-isp2-down owner=admin \ + policy=read,write,test source="\r\ + \n/ip firewall mangle disable [find comment=\"hybrid office PCC ISP2\"]\r\ + \n/ip firewall mangle disable [find comment=\"hybrid vpn PCC ISP2\"]\r\ + \n/ip firewall mangle disable [find comment=\"hybrid route ISP2\"]\r\ + \n/ip firewall mangle enable [find comment=\"hybrid office PCC ISP1\"]\r\ + \n/ip firewall mangle disable [find comment=\"hybrid vpn PCC ISP1\"]\r\ + \n/ip firewall mangle enable [find comment=\"hybrid route ISP1\"]\r\ + \n:log info \"HYBRID: mode ISP2-DOWN (office ISP1 only, VPN failover only)\ + \"\r\ + \n" +add dont-require-permissions=yes name=hybrid-sync-mode owner=admin policy=\ + read,write,test,sniff source="\r\ + \n:local up1 false\r\ + \n:local up2 false\r\ + \n:local ok1 0\r\ + \n:local ok2 0\r\ + \n:for i from=1 to=3 do={\r\ + \n :local r1 [/ping 117.102.73.97 count=1 as-value]\r\ + \n :if ([:typeof (\$r1->\"time\")] != \"nothing\") do={ :set ok1 (\$ok1 +\ + \_1) }\r\ + \n :local r2 [/ping 192.168.1.1 count=1 as-value]\r\ + \n :if ([:typeof (\$r2->\"time\")] != \"nothing\") do={ :set ok2 (\$ok2 +\ + \_1) }\r\ + \n}\r\ + \n:if (\$ok1 >= 2) do={ :set up1 true }\r\ + \n:if (\$ok2 >= 2) do={ :set up2 true }\r\ + \n:if (\$up1 && \$up2) do={\r\ + \n /system script run hybrid-set-mode-both-up\r\ + \n} else={\r\ + \n :if (!\$up1) do={\r\ + \n /system script run hybrid-set-mode-isp1-down\r\ + \n } else={\r\ + \n :if (!\$up2) do={\r\ + \n /system script run hybrid-set-mode-isp2-down\r\ + \n }\r\ + \n }\r\ + \n}\r\ + \n" +add dont-require-permissions=yes name=latency-monitor owner=admin policy=\ + read,write,test,sniff source="\r\ + \n:local hysteresis 10ms\r\ + \n:global bestWan\r\ + \n:global isp1Latency\r\ + \n:global isp2Latency\r\ + \n:global isp1Loss\r\ + \n:global isp2Loss\r\ + \n:if ([:typeof \$bestWan] = \"nothing\") do={ :set bestWan \"isp1\" }\r\ + \n:local t1 0ms\r\ + \n:local t2 0ms\r\ + \n:local ok1 0\r\ + \n:local ok2 0\r\ + \n:local i 0\r\ + \n:do {\r\ + \n :local r1 [/ping 117.102.73.97 count=1 as-value]\r\ + \n :if ([:typeof (\$r1->\"time\")] != \"nothing\") do={\r\ + \n :set t1 (\$t1 + (\$r1->\"time\"))\r\ + \n :set ok1 (\$ok1 + 1)\r\ + \n }\r\ + \n :local r2 [/ping 192.168.1.1 count=1 as-value]\r\ + \n :if ([:typeof (\$r2->\"time\")] != \"nothing\") do={\r\ + \n :set t2 (\$t2 + (\$r2->\"time\"))\r\ + \n :set ok2 (\$ok2 + 1)\r\ + \n }\r\ + \n :set i (\$i + 1)\r\ + \n} while=(\$i < 5)\r\ + \n:local avg1 9999ms\r\ + \n:local avg2 9999ms\r\ + \n:local loss1 100\r\ + \n:local loss2 100\r\ + \n:if (\$ok1 > 0) do={\r\ + \n :set avg1 (\$t1 / \$ok1)\r\ + \n :set loss1 (100 - ((\$ok1 * 100) / 5))\r\ + \n}\r\ + \n:if (\$ok2 > 0) do={\r\ + \n :set avg2 (\$t2 / \$ok2)\r\ + \n :set loss2 (100 - ((\$ok2 * 100) / 5))\r\ + \n}\r\ + \n:set isp1Latency \$avg1\r\ + \n:set isp2Latency \$avg2\r\ + \n:set isp1Loss \$loss1\r\ + \n:set isp2Loss \$loss2\r\ + \n:local newBest \$bestWan\r\ + \n:if (\$loss1>49 && \$loss2>49) do={\r\ + \n :log warning \"Latency Monitor: kedua ISP loss tinggi, tetap \$bestWan\ + \"\r\ + \n} else={\r\ + \n :if (\$loss2>49) do={ :set newBest \"isp1\" } else={\r\ + \n :if (\$loss1>49) do={ :set newBest \"isp2\" } else={\r\ + \n :if (\$avg1 < (\$avg2 - \$hysteresis)) do={ :set newBest \"isp1\" \ + } else={\r\ + \n :if (\$avg1 > (\$avg2 + \$hysteresis)) do={ :set newBest \"isp2\ + \" }\r\ + \n }\r\ + \n }\r\ + \n }\r\ + \n :set bestWan \$newBest\r\ + \n}\r\ + \n:log info (\"Latency Monitor: ISP1=\" . [:tostr \$avg1] . \" loss=\" . \ + \$loss1 . \"% | ISP2=\" . [:tostr \$avg2] . \" loss=\" . \$loss2 . \"% | b\ + est=\" . \$bestWan)\r\ + \n" +add dont-require-permissions=yes name=nas-backup owner=admin policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source="\ + \r\ + \n:global nasFtpHost \"10.100.1.10\"\r\ + \n:global nasFtpUser \"admin\"\r\ + \n:global nasFtpPass \"REDACTED_SEE_NAS_VAULT\"\r\ + \n:global nasFtpPath \"mainpve/mikrotik\"\r\ + \n:local bname \"nas-latest\"\r\ + \n:log info \"NAS backup: mulai\"\r\ + \n/system backup save name=\$bname\r\ + \n/export file=\$bname\r\ + \n:delay 2s\r\ + \n/tool fetch address=\$nasFtpHost mode=ftp user=\$nasFtpUser password=\$n\ + asFtpPass src-path=(\$bname . \".backup\") dst-path=(\$nasFtpPath . \"/\" \ + . \$bname . \".backup\") upload=yes\r\ + \n/tool fetch address=\$nasFtpHost mode=ftp user=\$nasFtpUser password=\$n\ + asFtpPass src-path=(\$bname . \".rsc\") dst-path=(\$nasFtpPath . \"/\" . \ + \$bname . \".rsc\") upload=yes\r\ + \n/file remove (\$bname . \".backup\")\r\ + \n/file remove (\$bname . \".rsc\")\r\ + \n:log info \"NAS backup: selesai\"\r\ + \n" +/tool netwatch +add comment="hybrid monitor ISP1" down-script=hybrid-set-mode-isp1-down host=\ + 117.102.73.97 interval=10s timeout=3s type=simple up-script=\ + hybrid-sync-mode +add comment="hybrid monitor ISP2" down-script=hybrid-set-mode-isp2-down host=\ + 192.168.1.1 interval=10s timeout=3s type=simple up-script=\ + hybrid-sync-mode diff --git a/Mikrotik/docs/adr/000-template.md b/Mikrotik/docs/adr/000-template.md new file mode 100644 index 0000000..e8dde6d --- /dev/null +++ b/Mikrotik/docs/adr/000-template.md @@ -0,0 +1,3 @@ +# ADR Template + +Salin untuk keputusan baru. Contoh: [ADR-0001-hybrid-dual-wan.md](./ADR-0001-hybrid-dual-wan.md). diff --git a/Mikrotik/docs/adr/ADR-0001-hybrid-dual-wan.md b/Mikrotik/docs/adr/ADR-0001-hybrid-dual-wan.md new file mode 100644 index 0000000..6478b2c --- /dev/null +++ b/Mikrotik/docs/adr/ADR-0001-hybrid-dual-wan.md @@ -0,0 +1,36 @@ +# ADR-0001: Hybrid Dual-WAN (failover + PCC office) + +| Field | Value | +|-------|-------| +| Status | Accepted (live) | +| Date | 2026-06-13 (verified 2026-07-06) | + +--- + +## Context + +Dua ISP: Biznet (ether1, IP publik statik) dan IDBiz (sfp-sfpplus1, DHCP). Butuh internet user kantor tetap jalan saat satu ISP down. + +--- + +## Decision + +- **Failover** default route main: ISP1 `check-gateway=ping`, backup ISP2 +- **Hybrid PCC** untuk office: scheduler `hybrid-sync-mode` + netwatch ISP1/ISP2 +- Routing tables `KE ISP 1` / `KE ISP 2` + mangle marks +- Script deploy: `server-connection/scripts/apply-hybrid-mikrotik.ps1` + +--- + +## Consequences + +**Positif:** Resiliensi ISP; office load-balance saat both up + +**Negatif:** Kompleksitas troubleshooting; perubahan salah bisa putus internet seluruh kantor + +--- + +## References + +- `server-connection/server/existing-network-geonet.txt` +- `backups/mikrotik-export-2026-07-06.rsc` diff --git a/Mikrotik/docs/ai-session-summary.md b/Mikrotik/docs/ai-session-summary.md new file mode 100644 index 0000000..1e36205 --- /dev/null +++ b/Mikrotik/docs/ai-session-summary.md @@ -0,0 +1,38 @@ +# AI Session Summary + +```yaml +session: 2026-07-06-mikrotik-bootstrap-audit +project: Mikrotik/ +version: 0.1.0 +status: ready +next: Verifikasi NAT mail gisportal.id vs Mailcow .28 setelah perubahan DNS +agent: Cursor +``` + +## TL;DR + +- Bootstrap repo `Mikrotik/` + **audit live** `10.100.1.1` (RouterOS 7.5, uptime ~1d) +- Mode jaringan: **hybrid dual-WAN** (ISP1 Biznet + ISP2 IDBiz) + failover `check-gateway=ping` +- Backup `/export compact` → `backups/mikrotik-export-2026-07-06.rsc` (NAS FTP pass **diredaksi**) +- Mail publik `117.102.73.102` → NAT ke Mailcow `10.100.1.28` (:25/:587/:993/:465) +- Chat sebelumnya: user tanya riwayat MikroTik — ada di `server-connection/`, belum di chat Cursor + +## Lanjut dari sini + +1. Dokumentasi NAT mail selaras Mailcow `gisportal.id` — [notes/nat-mail-gisportal.md](./notes/nat-mail-gisportal.md) +2. Sebelum ubah routing: backup baru + append `version.md` +3. Pertimbangkan nonaktifkan PPTP (legacy) + +## Jangan + +- Commit `nasFtpPass` atau PPP password plaintext +- Edit SPF/DKIM di MikroTik +- Import `.rsc` ke production tanpa maintenance window + +## Konteks chat (disimpan) + +| Topik | Ringkasan | +|-------|-----------| +| Riwayat MikroTik di chat | Belum troubleshoot eksplisit di Cursor; infra ada di `server-connection/server/` | +| Mailcow gisportal | MX langsung `.102`; NAT port email ke `.28` — DNS SPF di Master Web | +| SSH gagal tanpa key | `Permission denied` — wajib `id_rsa_mikrotik` | diff --git a/Mikrotik/docs/architecture/system-overview.md b/Mikrotik/docs/architecture/system-overview.md new file mode 100644 index 0000000..fac14d2 --- /dev/null +++ b/Mikrotik/docs/architecture/system-overview.md @@ -0,0 +1,128 @@ +# System Overview — MikroTik Gateway + +**Last updated:** 2026-07-06 +**Source:** Live SSH audit + `backups/mikrotik-export-2026-07-06.rsc` + +--- + +## Perangkat + +| Item | Nilai | +|------|-------| +| Hostname | MikroTik | +| Model | CCR2004-1G-12S+2XS (ARM64, 4 CPU) | +| RouterOS | 7.5 stable | +| RAM | 4032 MiB (~3820 free) | +| Serial | HDD08647CP6 | + +--- + +## Diagram tingkat tinggi + +``` + Internet + │ + ┌──────────────┴──────────────┐ + │ ISP1 Biznet (ether1) │ ISP2 IDBiz (sfp-sfpplus1, DHCP) + │ GW 117.102.73.97 │ GW 192.168.1.1 + └──────────────┬──────────────┘ + │ + ┌─────────▼─────────┐ + │ MikroTik .1 │ + │ hybrid failover │ + │ + PCC office │ + └─────────┬─────────┘ + ┌───────────────┼───────────────┐ + │ │ │ + bridge:server bridge:office bridge:vpn + 10.100.1.0/24 192.168.0.0/24 100.100.1.0/24 + │ │ │ + Proxmox, DB, User kantor, SSTP/PPTP + Mailcow .28, MULTIMEDIA .14 RADIUS→AD .40 + nginx .24, ... +``` + +--- + +## Segment jaringan + +| Segment | Gateway | Bridge / IF | DHCP | +|---------|---------|-------------|------| +| Server LAN | `10.100.1.1` | `server` | — | +| Office | `192.168.0.1` | `office` (sfp-sfpplus10) | dhcp1, lease 4w3d | +| VPN remote | `100.100.1.0` | `vpn` | dhcp2 | +| IBM (legacy) | `192.168.2.1` | vlan2004 | relay (inactive) | + +--- + +## WAN publik (blok `117.102.73.96/29`) + +| IP | Komentar | Fungsi utama | +|----|----------|--------------| +| `.102` | gisportal.id | Web/API/mail NAT → internal | +| `.99` | geonet.co.id | HTTP/S → `.24`; beberapa mail rule legacy | +| `.98` | geonet.co.id | — | +| `.100` | dev.gisportal.id | Dev/ArcGIS NAT | +| `.101` | Not Set | Mail legacy → `.76` | + +--- + +## Routing (aktif 2026-07-06) + +| Route | Tabel | Gateway | Catatan | +|-------|-------|---------|---------| +| `0.0.0.0/0` | main | `117.102.73.97` | **Primary**, `check-gateway=ping` | +| `0.0.0.0/0` | KE ISP 1/2 | hybrid tables | PCC / failover scripts | +| ISP2 WAN | sfp-sfpplus1 | `192.168.1.4/24` | DHCP dynamic — **UP** | + +Scheduler `hybrid-sync-mode` + netwatch ping ISP1/ISP2 menyesuaikan mangle PCC. + +--- + +## NAT penting (publik → internal) + +| Publik | Port | Internal | Service | +|--------|------|----------|---------| +| `.102` | 80, 443 | `10.100.1.24` | nginx reverse proxy | +| `.102` | 25, 587, 993, 465 | `10.100.1.28` | **Mailcow** | +| `.102` | 5432, 1433, … | `.25`, `.75`, … | DB / SQL (hati-hati expose) | +| `.99` | 80, 443 | `10.100.1.24` | geonet web | +| `.100` | 443, 6443, … | `.51`, `.57`, `.59` | ArcGIS dev | + +Mail **geonet.co.id** masih ada rule ke `.76` / `.40` (legacy cPanel/AD) — beberapa **disabled**. + +--- + +## VPN & auth + +| Protokol | Status | Auth | +|----------|--------|------| +| SSTP | enabled (:443) | RADIUS → `10.100.1.40` | +| PPTP | enabled ⚠️ | Legacy — disarankan matikan | +| PPP secrets | lokal + RADIUS | IP tetap `10.100.1.220–230` | + +--- + +## DNS + +- Forwarder: `203.142.82.222`, `203.142.84.222` +- **Split-DNS** static: `*.gisportal.id` → `10.100.1.24` (user office/VPN resolve internal) + +--- + +## Layanan management + +| Service | Port | Akses | +|---------|------|-------| +| SSH | **255** | Key RSA | +| Winbox | default | `10.100.1.0/24`, `192.168.0.0/24` | +| WWW/API | disabled | — | + +--- + +## Backup otomatis + +| Target | Jadwal | +|--------|--------| +| QNAP `10.100.1.10:mainpve/mikrotik/` | Daily 03:00 (scheduler) | +| Repo `Mikrotik/backups/` | Manual / sesi audit | diff --git a/Mikrotik/docs/changelog.md b/Mikrotik/docs/changelog.md new file mode 100644 index 0000000..ea22470 --- /dev/null +++ b/Mikrotik/docs/changelog.md @@ -0,0 +1,24 @@ +# Changelog — MikroTik + +--- + +## [0.1.0] - 2026-07-06 + +### Added + +- Repo `Mikrotik/` — SSOT gateway docs & backup +- `backups/mikrotik-export-2026-07-06.rsc` +- `docs/architecture/system-overview.md` +- `docs/notes/chat-context.md`, `nat-mail-gisportal.md` +- ADR hybrid dual-WAN + +### Security + +- Redacted NAS FTP password from committed `.rsc` + +--- + +## Planned + +- NAT cleanup documentation +- Automated sanitized backup script diff --git a/Mikrotik/docs/context-index.md b/Mikrotik/docs/context-index.md new file mode 100644 index 0000000..4c0b390 --- /dev/null +++ b/Mikrotik/docs/context-index.md @@ -0,0 +1,54 @@ +# Context Index — MikroTik + +> Cold start: [../AGENTS.md](../AGENTS.md) → [ai-session-summary.md](./ai-session-summary.md) → **STOP** + +--- + +## Zona A + +| Item | Value | +|------|-------| +| Nama | MikroTik Gateway | +| Path | `Mikrotik/` | +| Host | `10.100.1.1` / `192.168.0.1` | +| Model | CCR2004-1G-12S+2XS, RouterOS **7.5** | +| Versi docs | **0.1.0** — [version.md](./version.md) | +| Backup | [../backups/](../backups/) | +| SSH | port **255**, MAC **hmac-sha1** | +| Last updated | 2026-07-06 | + +--- + +## Zona B + +| Dokumen | Isi | +|---------|-----| +| [architecture/system-overview.md](./architecture/system-overview.md) | Segment, WAN, alur traffic | +| [server.md](./server.md) | SSH, interface, layanan | +| [notes/nat-mail-gisportal.md](./notes/nat-mail-gisportal.md) | NAT email `.102` → Mailcow | +| [notes/chat-context.md](./notes/chat-context.md) | Ringkasan chat terkait MikroTik | +| [guide/migration.md](./guide/migration.md) | Restore / ganti router | +| [adr/ADR-0001-hybrid-dual-wan.md](./adr/ADR-0001-hybrid-dual-wan.md) | Keputusan dual-WAN | + +### Legacy (server-connection) + +| Path | Catatan | +|------|---------| +| `server-connection/server/mikrotik-audit.txt` | Audit 2026-06-13 | +| `server-connection/server/existing-network-geonet.txt` | Baseline failover | +| `server-connection/scripts/ssh-mikrotik.ps1` | SSH helper | + +### Sibling + +| Repo | Relasi | +|------|--------| +| Mailcow | NAT :25/:587/:993 ke `.28` | +| nginx | `.24` reverse proxy :80/:443 | +| server-connection | Script deploy hybrid/failover | + +--- + +## Aturan AI + +- Backup sebelum ubah NAT/routing +- Redaksi secret di `.rsc` sebelum commit diff --git a/Mikrotik/docs/guide/README.md b/Mikrotik/docs/guide/README.md new file mode 100644 index 0000000..641bb0e --- /dev/null +++ b/Mikrotik/docs/guide/README.md @@ -0,0 +1,16 @@ +# Guides — MikroTik + +| Guide | Path | +|-------|------| +| Restore / ganti router | [migration.md](./migration.md) | +| SSH setup | `server-connection/scripts/setup-ssh-mikrotik.ps1` | +| Deploy failover | `server-connection/scripts/apply-failover-mikrotik.ps1` | + +## Operasi cepat + +```routeros +/system resource print +/ip route print where active +/ip firewall nat print +/export compact +``` diff --git a/Mikrotik/docs/guide/migration.md b/Mikrotik/docs/guide/migration.md new file mode 100644 index 0000000..cd7a4d2 --- /dev/null +++ b/Mikrotik/docs/guide/migration.md @@ -0,0 +1,51 @@ +# Migration / Restore — MikroTik + +**Owner:** prosedur ganti router atau recovery config. +Backup: [../backups/README.md](../../backups/README.md). + +--- + +## Sebelum perubahan + +1. Export baru: `/export compact file=pre-change` +2. Salin ke repo `Mikrotik/backups/` (redaksi secret) +3. Append [../version.md](../version.md) + +--- + +## Restore dari repo `.rsc` + +1. Maintenance window — koordinasi user kantor +2. Upload file ke router (Winbox / `scp` jika enabled) +3. `/import file-name=mikrotik-export-YYYY-MM-DD.rsc` +4. Verifikasi: + - Ping `117.102.73.97` dari router + - User office internet + - NAT spot-check: `curl` web publik, test SMTP ke mail + +--- + +## Restore dari NAS `.backup` + +1. Download `mainpve/mikrotik/nas-latest.backup` dari QNAP +2. Upload ke router +3. `/system backup load name=nas-latest` + +--- + +## Ganti hardware router + +| Step | Action | +|------|--------| +| 1 | Catat MAC/interface mapping | +| 2 | Import config atau konfigurasi manual per segment | +| 3 | Update DHCP jika perlu | +| 4 | Tes dual-WAN failover | + +--- + +## Riwayat + +| Tanggal | Event | Catatan | +|---------|-------|---------| +| 2026-07-06 | Snapshot repo | `mikrotik-export-2026-07-06.rsc` | diff --git a/Mikrotik/docs/issues.md b/Mikrotik/docs/issues.md new file mode 100644 index 0000000..a762b44 --- /dev/null +++ b/Mikrotik/docs/issues.md @@ -0,0 +1,23 @@ +# Issues — MikroTik + +## Open + +### ISS-001: PPTP masih enabled (2026-07-06) + +- Protokol tidak aman — gunakan SSTP saja + +### ISS-002: Port DB/SQL expose ke publik `.102` (2026-07-06) + +- NAT :5432, :1433, dll. — review apakah masih diperlukan + +### ISS-003: NAS FTP password di script router (2026-07-06) + +- Plaintext di `nas-backup` script — pindah ke vault / rotasi + +### ISS-004: Legacy NAT mail `.76` / `.40` (2026-07-06) + +- Overlap dengan Mailcow `.28` — audit rule disabled vs aktif + +## Resolved + +_(belum ada)_ diff --git a/Mikrotik/docs/notes/chat-context.md b/Mikrotik/docs/notes/chat-context.md new file mode 100644 index 0000000..82556cc --- /dev/null +++ b/Mikrotik/docs/notes/chat-context.md @@ -0,0 +1,58 @@ +# Chat Context — MikroTik + +Ringkasan percakapan Cursor yang relevan dengan MikroTik (disimpan ke repo). + +--- + +## 2026-07-06 — Apakah pernah troubleshoot MikroTik? + +**Pertanyaan user:** Apakah pernah koneksi/troubleshoot `ssh -m hmac-sha1 admin@10.100.1.1 -p 255`? + +**Jawaban:** + +- Di **chat Cursor** sampai saat itu: **belum** ada sesi troubleshoot MikroTik eksplisit. +- Di **repo** sudah ada dokumentasi & skrip dari pekerjaan sebelumnya (Juni 2026): + - `server-connection/server/mikrotik-audit.txt` + - `existing-network-geonet.txt` + - `apply-failover-mikrotik.ps1`, `apply-hybrid-mikrotik.ps1` + - `server-audit/host.md` — perintah SSH + +**Temu teknis:** SSH tanpa key `id_rsa_mikrotik` → `Permission denied (publickey,password)`. + +--- + +## 2026-07-06 — Bootstrap repo Mikrotik + +**Permintaan user:** + +1. Audit arsitektur MikroTik live +2. Backup config ke repo +3. Dokumentasi AI-Agent-Standards + +**Hasil:** + +- Export `mikrotik-export-2026-07-06.rsc` (635 baris) +- Mode: hybrid dual-WAN aktif, ISP2 DHCP up +- Mail `.102` → `.28` verified di NAT rules +- Password NAS di script backup **diredaksi** sebelum commit + +--- + +## Konteks lintas-project (Mailcow) + +- User disarankan **tidak** edit SPF di MikroTik — DNS di Master Web. +- `gisportal.id` MX langsung ke IP publik; NAT email di MikroTik ke Mailcow VM. + +--- + +## Perintah SSH standar + +```powershell +# Dengan key (disarankan) +.\server-connection\scripts\ssh-mikrotik.ps1 + +# Manual +ssh -i "$env:USERPROFILE\.ssh\id_rsa_mikrotik" -o IdentitiesOnly=yes -m hmac-sha1 admin@10.100.1.1 -p 255 +``` + +Office LAN alternatif: `admin@192.168.0.1 -p 255` diff --git a/Mikrotik/docs/notes/nat-mail-gisportal.md b/Mikrotik/docs/notes/nat-mail-gisportal.md new file mode 100644 index 0000000..f455fcf --- /dev/null +++ b/Mikrotik/docs/notes/nat-mail-gisportal.md @@ -0,0 +1,58 @@ +# NAT Mail — gisportal.id / 117.102.73.102 + +> Konteks Mailcow: `Mailcow/docs/notes/gisportal-id-mail.md` + +--- + +## Arsitektur saat ini (2026-07-06) + +``` +Internet MX → mail.gisportal.id → 117.102.73.102 + │ + MikroTik dst-nat + │ + 10.100.1.28 (Mailcow) + :25 :587 :993 :465 +``` + +| Publik `.102` | → Internal `.28` | Protokol | +|---------------|-------------------|----------| +| 25 | 25 | SMTP | +| 587 | 587 | Submission | +| 993 | 993 | IMAPS | +| 465 | 465 | SMTPS | + +--- + +## Yang **tidak** di MikroTik + +| Item | Lokasi benar | +|------|--------------| +| SPF `gisportal.id` | Master Web DNS | +| DKIM TXT | Master Web DNS | +| Mailbox / transport | Mailcow VM | + +--- + +## Legacy geonet.co.id + +NAT masih ada ke: + +- `10.100.1.76` — mail hosting lama (port 25/143/993/587) +- `10.100.1.40` — beberapa rule **disabled** (AD) + +Hybrid Mailcow `geonet.co.id` masih MX cPanel — NAT `.99` ke `.24` untuk web. + +--- + +## Troubleshooting + +| Gejala | Cek | +|--------|-----| +| Mail tidak masuk gisportal | NAT `.102:25` → `.28`; firewall filter forward | +| TLS mail gagal | Cert di Mailcow/nginx, bukan di MikroTik | +| SPF fail | DNS registrar, bukan router | + +```routeros +/ip firewall nat print where dst-address=117.102.73.102 +``` diff --git a/Mikrotik/docs/project-status.md b/Mikrotik/docs/project-status.md new file mode 100644 index 0000000..3445150 --- /dev/null +++ b/Mikrotik/docs/project-status.md @@ -0,0 +1,41 @@ +# Project Status — MikroTik + +> **Versi:** 0.1.0 — [version.md](./version.md) +> **Last updated:** 2026-07-06 + +--- + +## Ringkasan + +Gateway perimeter GeoNet beroperasi **normal** — hybrid dual-WAN dengan failover otomatis, NAT publik ke stack internal, split-DNS gisportal. + +--- + +## Status + +| Area | Status | +|------|--------| +| Router live | ✅ uptime ~1d, CPU ~8% | +| ISP1 primary | ✅ `check-gateway=ping` | +| ISP2 backup | ✅ DHCP `192.168.1.4` | +| NAT web `.102` → `.24` | ✅ | +| NAT mail `.102` → `.28` | ✅ | +| Backup repo | ✅ 2026-07-06 | +| Backup NAS harian | ✅ scheduler | +| Dokumentasi SSOT | ✅ repo `Mikrotik/` | + +--- + +## Risiko terbuka + +| Item | Severity | +|------|----------| +| PPTP enabled | Medium (legacy insecure) | +| DB port expose publik | High — review firewall | +| Secret NAS di script router | Medium — rotasi + vault | + +--- + +## Next + +[todo.md](./todo.md) diff --git a/Mikrotik/docs/server.md b/Mikrotik/docs/server.md new file mode 100644 index 0000000..c1b29b7 --- /dev/null +++ b/Mikrotik/docs/server.md @@ -0,0 +1,65 @@ +# Server Inventory — MikroTik + +**Project:** `Mikrotik/` +**Last updated:** 2026-07-06 + +--- + +## Host + +| Field | Value | +|-------|-------| +| IP server LAN | `10.100.1.1/24` | +| IP office | `192.168.0.1/24` | +| IP VPN pool | `100.100.1.0/24` | +| Model | CCR2004-1G-12S+2XS | +| RouterOS | 7.5 | +| SSH | port **255**, user `admin` | + +--- + +## SSH + +| Metode | Command | +|--------|---------| +| Script | `server-connection/scripts/ssh-mikrotik.ps1` | +| Key | `~/.ssh/id_rsa_mikrotik` | +| MAC | `hmac-sha1` (wajib OpenSSH modern → RouterOS 7.5) | +| Office | `admin@192.168.0.1 -p 255` | + +Setup key: `server-connection/scripts/setup-ssh-mikrotik.ps1 -KeyType rsa` + +--- + +## Interface fisik (ringkas) + +| Port | Bridge | Keterangan | +|------|--------|------------| +| ether1 | WAN | ISP Biznet | +| sfp-sfpplus1 | WAN | ISP IDBiz (DHCP) | +| sfp-sfpplus2–5 | server | DELL, IBM, NAS | +| sfp-sfpplus10–11 | office | Switch kantor | +| sfp-sfpplus12 | office (disabled) | Switch adm | + +--- + +## Mapping monorepo + +| Fungsi | Internal IP | Repo | +|--------|-------------|------| +| Reverse proxy | `10.100.1.24` | nginx, server-connection | +| PostgreSQL | `10.100.1.25` | server-connection | +| Mailcow | `10.100.1.28` | Mailcow | +| AD/LDAP | `10.100.1.40` | server-connection, Zammad | +| QNAP NAS | `10.100.1.10` | server-connection | + +--- + +## Backup & restore + +| Lokasi | File | +|--------|------| +| Repo | `Mikrotik/backups/mikrotik-export-*.rsc` | +| NAS | `mainpve/mikrotik/nas-latest.backup` / `.rsc` | + +Lihat [../backups/README.md](../backups/README.md). diff --git a/Mikrotik/docs/system-requirements.md b/Mikrotik/docs/system-requirements.md new file mode 100644 index 0000000..ac8e0a7 --- /dev/null +++ b/Mikrotik/docs/system-requirements.md @@ -0,0 +1,47 @@ +# System Requirements — MikroTik + +**Project:** `Mikrotik/` +**Tipe:** infra (network gateway) +**Last updated:** 2026-07-06 + +--- + +## Perangkat + +| Item | Spesifikasi | +|------|-------------| +| Hardware | MikroTik CCR2004-1G-12S+2XS | +| RouterOS | 7.5+ stable | +| CPU | ARM64 quad-core | + +--- + +## Akses admin (dari workstation) + +| Tool | Versi / catatan | +|------|-----------------| +| OpenSSH client | Windows 10+ / PowerShell | +| MAC algorithm | `hmac-sha1` (`-m hmac-sha1`) | +| SSH key | RSA `id_rsa_mikrotik` untuk RouterOS 7.5 | +| Winbox | Opsional, dari subnet server/office | + +--- + +## Variabel (`.env.example`) + +| Variabel | Contoh | +|----------|--------| +| `MIKROTIK_HOST` | `10.100.1.1` | +| `MIKROTIK_SSH_PORT` | `255` | +| `MIKROTIK_SSH_MAC` | `hmac-sha1` | +| `WAN_IP_PRIMARY` | `117.102.73.102` | + +**No hardcode** IP di script baru — gunakan env atau parameter script. + +--- + +## Dependency + +- ISP1: static `117.102.73.96/29` di ether1 +- ISP2: DHCP di sfp-sfpplus1 +- RADIUS: AD `10.100.1.40` untuk VPN diff --git a/Mikrotik/docs/todo.md b/Mikrotik/docs/todo.md new file mode 100644 index 0000000..6d1fb67 --- /dev/null +++ b/Mikrotik/docs/todo.md @@ -0,0 +1,34 @@ +# TODO — MikroTik + +> Last updated: 2026-07-06 + +--- + +## High Priority + +- [ ] Review NAT mail legacy `.76` / `.40` — disable jika tidak dipakai +- [ ] Dokumentasi rule NAT `.102` non-mail (5432, 1433) — risk expose + +--- + +## Medium Priority + +- [ ] Nonaktifkan PPTP server (gunakan SSTP saja) +- [ ] Automatisasi export backup ke repo (script + redaksi secret) +- [ ] Sinkronkan `server-connection/server/mikrotik-audit.txt` → arahkan ke repo ini + +--- + +## Low Priority + +- [ ] Monitor link flap sfp-sfpplus12 +- [ ] Evaluasi upgrade RouterOS > 7.5 (test lab dulu) + +--- + +## Selesai (Sesi Ini) + +- [x] Audit live `10.100.1.1` + arsitektur hybrid dual-WAN +- [x] Backup `mikrotik-export-2026-07-06.rsc` (redaksi NAS password) +- [x] Bootstrap repo `Mikrotik/` + chat context +- [x] Dokumentasi NAT mail → Mailcow `.28` diff --git a/Mikrotik/docs/version.md b/Mikrotik/docs/version.md new file mode 100644 index 0000000..ed1eced --- /dev/null +++ b/Mikrotik/docs/version.md @@ -0,0 +1,19 @@ +# Version History — MikroTik + +--- + +## [0.1.0] - 2026-07-06 + +- Bootstrap dokumentasi AI-Agent-Standards +- Audit live CCR2004 `10.100.1.1` (RouterOS 7.5) +- Backup `/export compact` → `backups/mikrotik-export-2026-07-06.rsc` +- Dokumentasi arsitektur hybrid dual-WAN + NAT mail Mailcow `.28` +- Redaksi `nasFtpPass` di export sebelum commit repo +- Chat context: riwayat MikroTik vs sesi Cursor + +--- + +## Planned + +- Cleanup NAT legacy mail geonet +- Disable PPTP diff --git a/Ollama/.env.example b/Ollama/.env.example new file mode 100644 index 0000000..1465ea3 --- /dev/null +++ b/Ollama/.env.example @@ -0,0 +1,24 @@ +# Ollama — template konfigurasi (AMAN di-commit) +# Copy ke .env lokal untuk script/dev — JANGAN commit .env berisi secret +# Consumer app (geonet-console) pakai variabel serupa di server .24 + +# --- Ollama server (VM aiopr) --- +OLLAMA_BASE_URL=http://10.100.1.26:11434 +OLLAMA_CHAT_MODEL=qwen2.5:7b +OLLAMA_EMBED_MODEL=nomic-embed-text +OLLAMA_TIMEOUT=120 + +# --- Server-side only (systemd override di 10.100.1.26) --- +# OLLAMA_HOST=0.0.0.0:11434 +# OLLAMA_MODELS=/data/ollama/models +# OLLAMA_NUM_PARALLEL=2 +# OLLAMA_MAX_LOADED_MODELS=2 + +# --- Indexer / project search (Fase berikutnya) --- +# PGVECTOR_HOST=10.100.1.25 +# PGVECTOR_PORT=5432 +# PGVECTOR_DB=geonet_project_search +# NAS_SMB_HOST=10.100.1.10 +# NAS_SMB_SHARE=project + +# Dokumentasi: docs/system-requirements.md, docs/server.md, docs/guide/migration.md diff --git a/Ollama/.gitignore b/Ollama/.gitignore new file mode 100644 index 0000000..f27fb12 --- /dev/null +++ b/Ollama/.gitignore @@ -0,0 +1,10 @@ +# Environment & secrets — never commit +.env +.env.* +!.env.example + +# OS / editor +.DS_Store +Thumbs.db +.idea/ +.vscode/ diff --git a/Ollama/AGENTS.md b/Ollama/AGENTS.md new file mode 100644 index 0000000..6702afc --- /dev/null +++ b/Ollama/AGENTS.md @@ -0,0 +1,39 @@ +# AGENTS.md — Cold Start + +> Project: `Ollama/` +> Sesi: [docs/ai-session-summary.md](./docs/ai-session-summary.md) +> Peta: [docs/context-index.md](./docs/context-index.md) +> Env: [.env.example](./.env.example) + +## Apa ini? + +VM inference AI on-premise (Ollama) di `10.100.1.26` (`aiopr`) — chat `qwen2.5:7b` + embedding `nomic-embed-text` untuk geonet-console / project search. **Tidak** di-expose ke internet. + +## Aturan kritis + +- **No hardcoded URL/IP** — consumer pakai `OLLAMA_BASE_URL` di `.env` (lihat `.env.example`) +- Port `11434` hanya VLAN `10.100.1.0/24` (UFW); jangan buka ke publik +- **Jangan** jalankan Ollama di `10.100.1.24` (resource penuh) +- No commit `.env` / secret NAS DB +- No commit kecuali user minta +- **Deploy / perubahan material:** append [docs/version.md](./docs/version.md) +- SSH ke VM wajib persetujuan user (`ssh ollama` / `root@10.100.1.26`) +- Pengetahuan penting **wajib ke docs** + +## Lanjut kerja + +``` +1. AGENTS.md → docs/ai-session-summary.md → STOP +2. docs/todo.md, docs/server.md, docs/api/overview.md +``` + +## Pointer + +| Butuh | Buka | +|-------|------| +| Priority | [docs/todo.md](./docs/todo.md) | +| Versi / audit | [docs/version.md](./docs/version.md) | +| API Ollama | [docs/api/overview.md](./docs/api/overview.md) | +| Consumer app | `server-connection/geonet-console/config/ollama.php` | +| Requirement project search | `server-connection/server/ollama-nas-project-search-requirements.md` | +| Migrasi VM | [docs/guide/migration.md](./docs/guide/migration.md) | diff --git a/Ollama/README.md b/Ollama/README.md new file mode 100644 index 0000000..006a97c --- /dev/null +++ b/Ollama/README.md @@ -0,0 +1,13 @@ +# Ollama — AI On-Premise (GeoNet) + +Inference lokal untuk Super Apps — tanpa data keluar jaringan internal. + +| Item | Nilai | +|------|-------| +| Host | `aiopr` — `10.100.1.26` | +| API | `http://10.100.1.26:11434` (VLAN only) | +| Chat model | `qwen2.5:7b` | +| Embed model | `nomic-embed-text` | +| Consumer | `server-connection/geonet-console` (Fase 4) | + +**AI entry point:** [`docs/context-index.md`](docs/context-index.md) diff --git a/Ollama/docker/pgvector/.env.example b/Ollama/docker/pgvector/.env.example new file mode 100644 index 0000000..00bc4b5 --- /dev/null +++ b/Ollama/docker/pgvector/.env.example @@ -0,0 +1,2 @@ +POSTGRES_USER=geonet_ai +POSTGRES_PASSWORD=changeme_strong_password diff --git a/Ollama/docker/pgvector/compose.yaml b/Ollama/docker/pgvector/compose.yaml new file mode 100644 index 0000000..bbda89a --- /dev/null +++ b/Ollama/docker/pgvector/compose.yaml @@ -0,0 +1,22 @@ +services: + pgvector: + image: pgvector/pgvector:pg16 + container_name: pgvector + restart: unless-stopped + environment: + POSTGRES_USER: ${POSTGRES_USER} + POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} + POSTGRES_DB: geonet_project_search + volumes: + - pgvector_data:/var/lib/postgresql/data + - ./init.sql:/docker-entrypoint-initdb.d/init.sql:ro + ports: + - "10.100.1.24:5433:5432" + healthcheck: + test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER} -d geonet_project_search"] + interval: 10s + timeout: 5s + retries: 5 + +volumes: + pgvector_data: diff --git a/Ollama/docker/pgvector/init.sql b/Ollama/docker/pgvector/init.sql new file mode 100644 index 0000000..484f8f2 --- /dev/null +++ b/Ollama/docker/pgvector/init.sql @@ -0,0 +1,41 @@ +-- Enable pgvector extension +CREATE EXTENSION IF NOT EXISTS vector; + +-- Table: indexed code chunks dari monorepo +CREATE TABLE IF NOT EXISTS code_chunks ( + id BIGSERIAL PRIMARY KEY, + repo TEXT NOT NULL, -- nama repo/subproject, e.g. 'server-connection' + file_path TEXT NOT NULL, -- path relatif dari root monorepo + language TEXT, -- php, ts, tsx, py, md, dll + start_line INTEGER, + end_line INTEGER, + content TEXT NOT NULL, -- teks chunk asli + embedding vector(768), -- nomic-embed-text output + indexed_at TIMESTAMPTZ DEFAULT NOW(), + checksum TEXT -- MD5 file untuk deteksi perubahan +); + +-- Table: user interaction memory +CREATE TABLE IF NOT EXISTS user_memory ( + id BIGSERIAL PRIMARY KEY, + username TEXT NOT NULL, -- LDAP username + pattern TEXT NOT NULL, -- kategori: 'email_izin', 'coding_php', dll + context JSONB, -- detail konteks (atasan, gaya, dll) + embedding vector(768), -- embedding dari interaksi + created_at TIMESTAMPTZ DEFAULT NOW(), + updated_at TIMESTAMPTZ DEFAULT NOW() +); + +-- Index HNSW untuk similarity search (lebih cepat dari IVFFlat) +CREATE INDEX IF NOT EXISTS code_chunks_embedding_idx + ON code_chunks USING hnsw (embedding vector_cosine_ops) + WITH (m = 16, ef_construction = 64); + +CREATE INDEX IF NOT EXISTS user_memory_embedding_idx + ON user_memory USING hnsw (embedding vector_cosine_ops) + WITH (m = 16, ef_construction = 64); + +-- Index biasa +CREATE INDEX IF NOT EXISTS code_chunks_repo_idx ON code_chunks (repo); +CREATE INDEX IF NOT EXISTS code_chunks_file_idx ON code_chunks (file_path); +CREATE INDEX IF NOT EXISTS user_memory_username_idx ON user_memory (username); diff --git a/Ollama/docs/adr/000-template.md b/Ollama/docs/adr/000-template.md new file mode 100644 index 0000000..b2d7280 --- /dev/null +++ b/Ollama/docs/adr/000-template.md @@ -0,0 +1,5 @@ +# ADR Template + +Salin file ini untuk keputusan arsitektur baru: `ADR-NNNN-judul-singkat.md`. + +Lihat [ADR-0001-dedicated-ollama-vm.md](./ADR-0001-dedicated-ollama-vm.md) sebagai contoh. diff --git a/Ollama/docs/adr/ADR-0001-dedicated-ollama-vm.md b/Ollama/docs/adr/ADR-0001-dedicated-ollama-vm.md new file mode 100644 index 0000000..9bee136 --- /dev/null +++ b/Ollama/docs/adr/ADR-0001-dedicated-ollama-vm.md @@ -0,0 +1,57 @@ +# ADR-0001: Dedicated VM untuk Ollama (bukan di reverse proxy) + +| Field | Value | +|-------|-------| +| Status | Accepted | +| Date | 2026-06-15 (konfirmasi audit 2026-07-06) | +| Author | Infrastructure / AI Agent | +| Version | 0.1.0 | + +--- + +## Context + +Super Apps butuh AI on-prem (chat + embedding) untuk project search & fitur internal. Kandidat host: `10.100.1.24` (nginx + banyak Docker) atau VM dedicated `10.100.1.26`. + +`10.100.1.24` hanya ~15 GB RAM dengan Docker penuh (Zammad, geonet-console, n8n, dll.). + +--- + +## Decision + +Jalankan **Ollama native di VM dedicated `10.100.1.26` (`aiopr`)**: + +- API bind `0.0.0.0:11434` dengan UFW **hanya** `10.100.1.0/24` +- **Tidak** reverse proxy publik ke Ollama +- Consumer (`geonet-console`) memanggil HTTP langsung via VLAN + +--- + +## Alternatives Considered + +| Alternatif | Pro | Con | +|------------|-----|-----| +| Ollama di `.24` | Satu host | RAM/CPU penuh; risiko ganggu layanan produksi | +| Cloud API (OpenAI) | Mudah | Data keluar jaringan — ditolak kebijakan | +| GPU server terpisah | Performa | Belum ada hardware; fase CPU dulu | + +--- + +## Consequences + +**Positif:** +- Isolasi resource inference +- Data tetap on-prem +- VM sudah live dengan model production + +**Negatif / Trade-off:** +- Satu VM lagi untuk maintain +- CPU inference lebih lambat dari GPU +- Perlu update `OLLAMA_BASE_URL` di consumer saat pindah IP + +--- + +## References + +- `server-connection/server/ollama-nas-project-search-requirements.md` +- `Ollama/docs/server.md` (audit 2026-07-06) diff --git a/Ollama/docs/adr/ADR-001-ai-onprem-architecture.md b/Ollama/docs/adr/ADR-001-ai-onprem-architecture.md new file mode 100644 index 0000000..47fef12 --- /dev/null +++ b/Ollama/docs/adr/ADR-001-ai-onprem-architecture.md @@ -0,0 +1,109 @@ +# ADR-001: Arsitektur AI On-Premise — GPU Node + RAG + Memory + +> **Status:** Accepted +> **Tanggal:** 2026-07-06 +> **Decider:** Tim IT GIS Portal + +--- + +## Konteks + +Organisasi ingin mengimplementasikan AI on-premise yang bisa: +1. Membantu user membuat teks (email, laporan) dengan konteks personal +2. Menjawab pertanyaan tentang codebase dan infrastruktur +3. Membantu coding dan proses deploy +4. Belajar dari kebiasaan user (personalisasi) + +Semua ini harus berjalan **100% on-premise** tanpa mengirim data ke cloud. + +--- + +## Hardware yang Tersedia + +| Node | Spec | Peran | +|------|------|-------| +| PC-Multimedia `10.100.1.14` | Core Ultra 7 265K, 64 GB RAM, RTX 5060 Ti ~16 GB VRAM | **GPU inference node (utama)** | +| VM aiopr `10.100.1.26` | 48 vCPU, 62 GB RAM, no GPU | **CPU inference node (fallback)** | +| PostgreSQL `10.100.1.25` | — | **Vector DB (pgvector)** | + +--- + +## Keputusan + +### 1. Dual-node Ollama + +- **PC-Multimedia** = node utama GPU inference → model besar (14B), cepat +- **VM .26** = fallback CPU inference + background embedding/indexing +- Consumer (geonet-console) default ke PC-Multimedia, fallback ke VM .26 + +### 2. Tiga Level AI Capability (implementasi bertahap) + +#### Level 1 — Context Injection (Fase 1) +Profil user LDAP (nama, jabatan, atasan) di-inject ke system prompt setiap request. +- Effort: rendah +- Value: tinggi — AI langsung "kenal" user + +#### Level 2 — RAG + Memory (Fase 2–3) +- **Codebase RAG:** seluruh repo di-index ke pgvector (`geonet_project_search`), di-retrieve saat relevan +- **User Memory:** pola interaksi per user disimpan ke DB, di-retrieve untuk personalisasi +- Contoh: user sering minta template email ke Pak Taufik → AI ingat gaya & penerima + +#### Level 3 — Deploy Agent (Fase 4, opsional) +AI dengan tool calling: bisa SSH ke server, `docker exec`, `php artisan`, git — untuk bantu deploy otomatis. + +### 3. Model yang Dipilih + +| Tujuan | Model | VRAM | +|--------|-------|------| +| Coding & deploy assist | `qwen2.5-coder:14b` | ~9 GB | +| Chat umum / email / teks | `qwen2.5:14b` | ~9 GB | +| Embedding / RAG | `nomic-embed-text` | ~0.3 GB | +| Fallback ringan | `qwen2.5:7b` (di VM .26) | ~5 GB CPU | + +### 4. Storage Model + +Model disimpan di `T:\ollama\models` (Samsung SSD 9100 PRO 2TB, 323 GB free) — drive tercepat di PC-Multimedia. + +--- + +## Konsekuensi + +### Positif +- Privasi penuh — kode dan data user tidak keluar jaringan +- Biaya operasional nol (hardware sudah ada) +- Latensi rendah (LAN lokal) +- Bisa index seluruh codebase tanpa batas token cloud + +### Negatif / Risiko +- PC-Multimedia adalah workstation, bukan server — availability tergantung PC nyala +- Kualitas model 14B di bawah GPT-4/Claude untuk task kompleks +- Fine-tuning (Level 3+) butuh data latih yang cukup banyak +- GPU inference hanya bisa 1 request sekaligus (VRAM shared) + +### Mitigasi +- Power plan PC-Multimedia: "High Performance", disable sleep +- Fallback otomatis ke VM .26 jika PC-Multimedia tidak reachable +- Fine-tuning hanya untuk template spesifik, bukan model utama + +--- + +## Alternatif yang Ditolak + +| Alternatif | Alasan ditolak | +|------------|----------------| +| Full cloud (OpenAI/Anthropic) | Kode dikirim ke luar, biaya bulanan | +| Fine-tuning sebagai langkah pertama | Overkill untuk kasus email/chat; RAG sudah cukup | +| Hanya VM .26 (tanpa GPU) | Lambat untuk model 14B, tidak ada GPU | + +--- + +## Roadmap Implementasi + +``` +Fase 1 (1-2 hari) Install Ollama GPU di PC-Multimedia +Fase 2 (3-5 hari) pgvector + indexer codebase monorepo +Fase 3 (1 minggu) Integrasi geonet-console: /api/v1/ai/chat + user memory +Fase 4 (opsional) Deploy agent: tool calling SSH/docker +``` + +Detail task → [docs/todo.md](../todo.md) diff --git a/Ollama/docs/ai-session-summary.md b/Ollama/docs/ai-session-summary.md new file mode 100644 index 0000000..bd26c77 --- /dev/null +++ b/Ollama/docs/ai-session-summary.md @@ -0,0 +1,54 @@ +# AI Session Summary + +```yaml +session: 2026-07-06-ai-onprem-fase3 +project: Ollama/ +version: 0.4.0 +status: fase1+2+3-selesai +next: UI chat Super Apps PWA + user memory +agent: Cascade +``` + +## TL;DR + +- **Fase 1 ✅** — Ollama v0.31.1 GPU aktif di PC-Multimedia `10.100.1.14`, `qwen2.5-coder:14b` 11.5 GB VRAM +- **Fase 2 ✅** — pgvector Docker `10.100.1.24:5433`, DB `geonet_project_search`, 1.784 chunks dari 1.031 files +- **Fase 3 ✅** — `POST /api/v1/ai/chat` live di geonet-console, RAG end-to-end verified +- Bug selama deploy: `config/api.php` tertimpa `routes/api.php` saat scp glob → sudah fix + rebuild image + +## Infrastruktur aktif + +| Node | Alamat | Fungsi | +|------|--------|--------| +| PC-Multimedia | `10.100.1.14:11434` | Ollama GPU, `qwen2.5-coder:14b` + `nomic-embed-text` | +| pgvector Docker | `10.100.1.24:5433` | DB `geonet_project_search`, user `geonet_ai` | +| geonet-console | `10.100.1.24` Docker | Laravel 11, endpoint `/api/v1/ai/chat` | +| VM .26 | `10.100.1.26:11434` | Fallback CPU, `qwen2.5:7b` | + +## Files baru di geonet-console (sesi ini) + +- `app/Services/AiChatService.php` — embed → pgvector → Ollama chat +- `app/Http/Controllers/Api/V1/AiChatController.php` — REST handler +- `config/pgvector.php` — reads `PGVECTOR_*` env vars +- `config/ollama.php` — updated default ke `10.100.1.14:11434` + `qwen2.5-coder:14b` + +## Indexer (Ollama/indexer/) + +- `indexer.py` — crawl monorepo, chunk 80 baris, embed nomic-embed-text, insert pgvector +- `requirements.txt` — `psycopg[binary]`, `requests`, `python-dotenv` +- `.env.example` — `OLLAMA_BASE_URL`, `PGVECTOR_*`, `REPO_ROOT`, `CHUNK_SIZE=80` +- Jalankan ulang: `python indexer.py` dari folder `Ollama/indexer/` dengan `.env` aktif + +## Lanjut dari sini + +1. **UI chat** di Super Apps PWA — React component, `POST /api/v1/ai/chat`, streaming optional +2. **User memory** — endpoint simpan/load dari tabel `user_memory` di pgvector +3. **Re-index otomatis** — cron harian atau webhook git post-receive +4. **Permission guard** — tambah `ai.chat` ke LDAP group permissions + +## Jangan + +- Expose port 11434 ke internet / reverse proxy publik +- Jalankan Ollama di `10.100.1.24` +- Simpan secret/password di repo — hanya `.env.example` +- Gunakan scp glob `config/*.php routes/*.php` ke folder berbeda — file bisa tertimpa diff --git a/Ollama/docs/api/README.md b/Ollama/docs/api/README.md new file mode 100644 index 0000000..844f050 --- /dev/null +++ b/Ollama/docs/api/README.md @@ -0,0 +1,37 @@ +# API Documentation — Ollama + +**Owner:** kontrak HTTP API Ollama di VM internal. +Dokumentasi resmi: [Ollama API](https://github.com/ollama/ollama/blob/main/docs/api.md) + +Consumer GeoNet: `server-connection/geonet-console` (`OllamaService.php`). + +--- + +## Base URL + +| Env | URL | Env var | +|-----|-----|---------| +| VLAN prod | `http://10.100.1.26:11434` | `OLLAMA_BASE_URL` | + +--- + +## Indeks Endpoint (sering dipakai) + +| Method | Path | Deskripsi | Auth | +|--------|------|-----------|------| +| GET | `/api/version` | Versi Ollama | none | +| GET | `/api/tags` | Daftar model | none | +| POST | `/api/chat` | Chat completion | none | +| POST | `/api/generate` | Text generation | none | +| POST | `/api/embeddings` | Vector embedding | none | + +Detail: [overview.md](./overview.md) + +--- + +## Konvensi GeoNet + +- Chat model default: `qwen2.5:7b` +- Embed model default: `nomic-embed-text` +- Timeout client: `OLLAMA_TIMEOUT` (default 120s) +- **Tidak** expose API ke internet diff --git a/Ollama/docs/api/overview.md b/Ollama/docs/api/overview.md new file mode 100644 index 0000000..d140b10 --- /dev/null +++ b/Ollama/docs/api/overview.md @@ -0,0 +1,94 @@ +# Ollama HTTP API — Overview + +Base: `OLLAMA_BASE_URL` (default `http://10.100.1.26:11434`) + +--- + +## Health / version + +```bash +curl -s http://10.100.1.26:11434/api/version +# {"version":"0.30.8"} +``` + +```bash +curl -s http://10.100.1.26:11434/api/tags +``` + +--- + +## Chat (`POST /api/chat`) + +Model: `qwen2.5:7b` + +```bash +curl -s http://10.100.1.26:11434/api/chat -d '{ + "model": "qwen2.5:7b", + "messages": [{"role": "user", "content": "Halo"}], + "stream": false +}' +``` + +--- + +## Embeddings (`POST /api/embeddings`) + +Model: `nomic-embed-text` + +```bash +curl -s http://10.100.1.26:11434/api/embeddings -d '{ + "model": "nomic-embed-text", + "prompt": "teks untuk di-embed" +}' +``` + +Response: array `embedding` (768 dimensi untuk `nomic-embed-text`). + +--- + +## Generate (`POST /api/generate`) + +Alternatif non-chat (prompt tunggal): + +```bash +curl -s http://10.100.1.26:11434/api/generate -d '{ + "model": "qwen2.5:7b", + "prompt": "Jelaskan SPF record", + "stream": false +}' +``` + +--- + +## Integrasi geonet-console + +| File | Fungsi | +|------|--------| +| `config/ollama.php` | Env mapping | +| `app/Services/OllamaService.php` | HTTP client | + +Env di server `.24` (contoh): + +```env +OLLAMA_BASE_URL=http://10.100.1.26:11434 +OLLAMA_CHAT_MODEL=qwen2.5:7b +OLLAMA_EMBED_MODEL=nomic-embed-text +OLLAMA_TIMEOUT=120 +``` + +--- + +## Error umum + +| Gejala | Penyebab | Tindakan | +|--------|----------|----------| +| Connection refused | Ollama down / UFW | `systemctl status ollama`, cek UFW | +| Timeout | Model besar + prompt panjang | Naik `OLLAMA_TIMEOUT`, kurangi context | +| 404 model | Belum pull | `ollama pull ` di VM | + +--- + +## Security + +- API **tanpa auth** — andalkan network segmentation (VLAN only) +- Jangan tambahkan reverse proxy publik tanpa auth layer diff --git a/Ollama/docs/changelog.md b/Ollama/docs/changelog.md new file mode 100644 index 0000000..ba6da58 --- /dev/null +++ b/Ollama/docs/changelog.md @@ -0,0 +1,56 @@ +# Changelog — Ollama + +Format [Keep a Changelog](https://keepachangelog.com/). Ringkasan: [version.md](./version.md). + +--- + +## [0.1.0] - 2026-07-06 + +### Added + +- Struktur dokumentasi standar AI-Agent-Standards +- Audit live VM `10.100.1.26` (Ollama 0.30.8, models, UFW, connectivity) +- `docs/server.md`, `docs/api/overview.md`, ADR dedicated VM + +### Verified + +- Ollama systemd active; API `11434` merespons +- Models: `qwen2.5:7b`, `nomic-embed-text:latest` + +--- + +## [0.4.0] - 2026-07-06 + +### Added + +- **Fase 2:** pgvector Docker di `10.100.1.24:5433` (pgvector 0.8.4/pg16) +- DB `geonet_project_search`, tabel `code_chunks` + `user_memory`, HNSW cosine index 768-dim +- `Ollama/indexer/indexer.py` — crawl monorepo, chunk 80 baris, embed nomic-embed-text, insert pgvector +- `Ollama/docker/pgvector/compose.yaml` + `init.sql` + `.env.example` +- **Fase 3:** `AiChatService` + `AiChatController` di geonet-console +- Endpoint `POST /api/v1/ai/chat` + `GET /api/v1/ai/status` +- `config/pgvector.php` — baca env `PGVECTOR_*` +- `config/ollama.php` default diupdate ke `10.100.1.14:11434` + `qwen2.5-coder:14b` + +### Verified + +- 1.784 chunks dari 1.031 files, 18 repo berhasil diindeks +- Similarity search akurat (query → FeedbackController.php top result) +- End-to-end: query → embed → pgvector → 5 chunks → Ollama → jawaban akurat + +### Fixed + +- `config/api.php` tertimpa `routes/api.php` saat scp glob — fixed + rebuild image +- APP_KEY kosong setelah `--no-cache` rebuild — generate manual via Python + +--- + +## [0.2.0] - 2026-07-06 + +### Added + +- Fase 1: Ollama v0.31.1 GPU di PC-Multimedia `10.100.1.14` +- Model `qwen2.5-coder:14b` + `nomic-embed-text` di `T:\ollama\models` +- Autostart Task Scheduler SYSTEM + Firewall VLAN-only + +--- diff --git a/Ollama/docs/context-index.md b/Ollama/docs/context-index.md new file mode 100644 index 0000000..fe0bbe9 --- /dev/null +++ b/Ollama/docs/context-index.md @@ -0,0 +1,72 @@ +# Context Index — Ollama + +> Cold start: [../AGENTS.md](../AGENTS.md) → [ai-session-summary.md](./ai-session-summary.md) → **STOP** + +--- + +## Zona A — Always-read pointers + +| Item | Value | +|------|-------| +| Nama | Ollama (AI on-prem) | +| Path monorepo | `Ollama/` | +| Deskripsi | Inference Ollama CPU di VM dedicated | +| Stack | Ollama native (systemd), tanpa Docker | +| Tipe | infra | +| Versi | **0.1.0** — [version.md](./version.md) | +| Host | `aiopr` `10.100.1.26` | +| API | `:11434` (VLAN `10.100.1.0/24`) | +| Cold start | [../AGENTS.md](../AGENTS.md) | +| Sesi terakhir | [ai-session-summary.md](./ai-session-summary.md) | +| Priority | [todo.md](./todo.md) | +| Server | [server.md](./server.md) | +| Last updated | 2026-07-06 | + +**Rolling session memory:** hanya [ai-session-summary.md](./ai-session-summary.md). + +--- + +## Zona B — On-demand map + +### Dokumentasi inti + +| Dokumen | Kapan baca | +|---------|------------| +| [project-status.md](./project-status.md) | Milestone & gap | +| [server.md](./server.md) | SSH, systemd, UFW, spesifikasi VM | +| [system-requirements.md](./system-requirements.md) | Runtime minimum | +| [issues.md](./issues.md) | Bug / limitation | +| [changelog.md](./changelog.md) | Riwayat | +| [version.md](./version.md) | Deploy / audit | +| [api/overview.md](./api/overview.md) | HTTP API Ollama | +| [guide/migration.md](./guide/migration.md) | Pindah VM / ganti IP | +| [adr/ADR-0001-dedicated-ollama-vm.md](./adr/ADR-0001-dedicated-ollama-vm.md) | Keputusan host | + +### Sibling / consumer + +| Repo | Entry | Relasi | +|------|-------|--------| +| server-connection | `geonet-console/config/ollama.php` | Consumer chat/embed | +| server-connection | `server/ollama-nas-project-search-requirements.md` | Requirement indexer | +| GeoNetAgent | `docs/roadmap.md` Fase 4 | Roadmap integrasi | + +--- + +## Arsitektur singkat + +``` +geonet-console (.24) ──HTTP──► Ollama (.26:11434) + │ │ + │ ├── qwen2.5:7b (chat) + │ └── nomic-embed-text (embedding) + └──► PostgreSQL .25 (pgvector — planned) +Indexer (planned) ──SMB RO──► QNAP .10 +``` + +--- + +## Aturan kritis AI + +- UFW: `11434` hanya dari `10.100.1.0/24` +- No reverse proxy publik untuk Ollama +- SSH wajib persetujuan user diff --git a/Ollama/docs/guide/README.md b/Ollama/docs/guide/README.md new file mode 100644 index 0000000..0faa45b --- /dev/null +++ b/Ollama/docs/guide/README.md @@ -0,0 +1,33 @@ +# Guide — Ollama + +| Guide | Isi | +|-------|-----| +| [migration.md](./migration.md) | Pindah VM / ganti IP Ollama | +| [server.md](../server.md) | Install, systemd, model pull | +| [api/overview.md](../api/overview.md) | HTTP API | + +## Operasi rutin + +```bash +# Status +systemctl status ollama +ollama list +ollama ps + +# Pull model baru +ollama pull qwen2.5:7b + +# Restart setelah ubah override systemd +systemctl daemon-reload && systemctl restart ollama +``` + +## Consumer setup (geonet-console) + +1. Edit `.env` di `10.100.1.24` — set `OLLAMA_BASE_URL` +2. Smoke test dari container/host `.24`: + +```bash +curl -s http://10.100.1.26:11434/api/version +``` + +3. Uji endpoint aplikasi yang memanggil `OllamaService` diff --git a/Ollama/docs/guide/migration.md b/Ollama/docs/guide/migration.md new file mode 100644 index 0000000..01fc486 --- /dev/null +++ b/Ollama/docs/guide/migration.md @@ -0,0 +1,67 @@ +# Migration Guide — Ollama VM + +**Owner:** prosedur pindah Ollama ke host/IP baru. +Inventori: [../server.md](../server.md). Env: [../../.env.example](../../.env.example). + +**Prinsip:** ubah `OLLAMA_BASE_URL` di consumer — bukan hardcode di kode. + +--- + +## Inventori sebelum migrasi + +| Item | Nilai saat ini | File yang diupdate | +|------|----------------|-------------------| +| Ollama host | `10.100.1.26` (`aiopr`) | `Ollama/docs/server.md`, `.env.example` | +| API URL | `http://10.100.1.26:11434` | geonet-console `.env` di `.24` | +| Model path | `/data/ollama/models` | systemd override | +| UFW | `11434` dari `10.100.1.0/24` | server UFW rules | + +--- + +## Variabel env terpengaruh + +| Variabel | Old | New | Lokasi | +|----------|-----|-----|--------| +| `OLLAMA_BASE_URL` | `http://10.100.1.26:11434` | `{new}` | geonet-console `.env` | +| `OLLAMA_HOST` | `0.0.0.0:11434` | (sama) | systemd `.26` | + +--- + +## Langkah migrasi VM + +1. **Persiapan VM baru** + - [ ] Ubuntu 22.04 Server, vCPU ≥ 16, RAM ≥ 32 GiB + - [ ] Install Ollama + buat `/data/ollama/models` + - [ ] UFW: 22 + 11434 dari VLAN saja + +2. **Salin model** (pilih salah satu) + - [ ] `rsync -av /data/ollama/models/` ke VM baru, atau + - [ ] `ollama pull` ulang di VM baru + +3. **Parallel test** + - [ ] `curl` `/api/version` dari `.24` + - [ ] Chat + embed smoke test + +4. **Cutover consumer** + - [ ] Update `OLLAMA_BASE_URL` di geonet-console `.env` + - [ ] Restart container geonet-console + +5. **Dokumentasi** + - [ ] Update `Ollama/docs/server.md`, `Workspace-Context.md` + - [ ] Append `version.md` + `changelog.md` + +--- + +## Rollback + +1. Kembalikan `OLLAMA_BASE_URL` ke IP lama +2. Restart consumer +3. Catat di `issues.md` + +--- + +## Riwayat migrasi + +| Tanggal | Dari | Ke | Catatan | +|---------|------|-----|---------| +| — | — | — | Belum ada migrasi | diff --git a/Ollama/docs/issues.md b/Ollama/docs/issues.md new file mode 100644 index 0000000..f1fa112 --- /dev/null +++ b/Ollama/docs/issues.md @@ -0,0 +1,21 @@ +# Issues — Ollama + +## Open + +### ISS-001: geonet-console belum pointing ke Ollama VM (2026-07-06) + +- `OLLAMA_BASE_URL` default masih `127.0.0.1:11434` di template +- Perlu set di `.env` server `10.100.1.24` + +### ISS-002: Indexer NAS belum ada (2026-07-06) + +- SMB mount ke `10.100.1.10` belum dikonfigurasi +- Lihat `server-connection/server/ollama-nas-project-search-requirements.md` + +### ISS-003: Ubuntu Desktop (2026-07-06) + +- VM masih Desktop 22.04 — disarankan Server atau matikan GUI untuk hemat resource + +## Resolved + +_(belum ada)_ diff --git a/Ollama/docs/project-status.md b/Ollama/docs/project-status.md new file mode 100644 index 0000000..aa9e3ee --- /dev/null +++ b/Ollama/docs/project-status.md @@ -0,0 +1,45 @@ +# Project Status — Ollama + +> **Terakhir Diperbarui:** 2026-07-06 +> **Versi:** 0.1.0 — [version.md](./version.md) + +--- + +## Ringkasan + +VM dedicated **AI inference on-prem** (`10.100.1.26`) untuk Super Apps — chat & embedding tanpa cloud API. Ollama sudah terinstall dan berjalan; integrasi aplikasi & indexer masih Fase berikutnya. + +--- + +## Status komponen + +| Komponen | Status | Catatan | +|----------|--------|---------| +| VM `aiopr` | ✅ | 48 vCPU, 62 GiB RAM, 503 GB disk | +| Ollama 0.30.8 + systemd | ✅ | Since 2026-06-15 | +| Model `qwen2.5:7b` | ✅ | Chat / RAG answer | +| Model `nomic-embed-text` | ✅ | Embedding 768-dim | +| UFW VLAN-only `:11434` | ✅ | `10.100.1.0/24` | +| Storage `/data/ollama/models` | ✅ | ~4.7 GB models | +| geonet-console consumer | ⏳ | `OLLAMA_BASE_URL` belum aktif di `.24` | +| SMB mount NAS indexer | ❌ | Requirement POC | +| pgvector `.25` | ❌ | `geonet_project_search` | +| GPU | N/A | CPU inference | + +--- + +## Audit vs requirement (2026-07-06) + +| Requirement | Doc lama (2026-06-15) | Live sekarang | +|-------------|----------------------|---------------| +| vCPU 16+ | ⚠️ 8 | ✅ **48** | +| Ollama install | ❌ | ✅ | +| Models pull | ❌ | ✅ | +| UFW 11434 VLAN | ❌ | ✅ | +| SMB mount | ❌ | ❌ | + +--- + +## Berikutnya + +Lihat [todo.md](./todo.md) — prioritas: aktifkan consumer geonet-console, indexer POC. diff --git a/Ollama/docs/server.md b/Ollama/docs/server.md new file mode 100644 index 0000000..704ae2a --- /dev/null +++ b/Ollama/docs/server.md @@ -0,0 +1,142 @@ +# Server Inventory — Ollama + +**Project:** `Ollama/` +**Last updated:** 2026-07-06 +**Credential location:** SSH key lokal (`~/.ssh/id_rsa_geonet_laptop`) — bukan secret di repo + +--- + +## Ringkasan + +| Field | Value | +|-------|-------| +| Hostname | `aiopr` | +| IP | `10.100.1.26/24` (`ens18`) | +| Role | AI inference (Ollama CPU) | +| OS | Ubuntu 22.04.5 LTS (Desktop) | +| Hypervisor | KVM | + +--- + +## Spesifikasi hardware (audit 2026-07-06) + +| Resource | Nilai | +|----------|-------| +| CPU | 48× Intel Xeon E5-2699 v4 @ 2.20GHz (AVX2) | +| RAM | 62 GiB (~60 GiB available idle) | +| Disk `/` | 503 GB SSD (`/dev/sda3`), ~5% used | +| GPU | Tidak ada (virtual VGA `1234:1111`) | +| Model storage | `/data/ollama/models` (~4.7 GB) | + +--- + +## Aplikasi & Runtime + +| Host | Aplikasi | Jenis | Port | Path / Unit | Catatan | +|------|----------|-------|------|-------------|---------| +| `.26` | Ollama | systemd | `11434` | `ollama.service` | User `ollama` | +| `.26` | sshd | systemd | `22` | — | Key-based | + +### systemd override (`/etc/systemd/system/ollama.service.d/override.conf`) + +```ini +Environment=OLLAMA_HOST=0.0.0.0:11434 +Environment=OLLAMA_MODELS=/data/ollama/models +Environment=OLLAMA_NUM_PARALLEL=2 +Environment=OLLAMA_MAX_LOADED_MODELS=2 +``` + +### Model terpasang + +| Model | Ukuran | Dipakai untuk | +|-------|--------|---------------| +| `qwen2.5:7b` | 4.7 GB | Chat / RAG generation | +| `nomic-embed-text:latest` | 274 MB | Embedding (768-dim) | + +--- + +## Firewall (UFW) + +| Port | Action | From | +|------|--------|------| +| 22/tcp | ALLOW | Anywhere | +| 11434/tcp | ALLOW | `10.100.1.0/24` | + +**Tidak** expose `11434` ke internet. + +--- + +## Konektivitas (dari VM) + +| Target | Port | Status | +|--------|------|--------| +| `10.100.1.25` PostgreSQL | 5432 | OK | +| `10.100.1.10` QNAP SMB | 445 | OK | +| `10.100.1.24` geonet-console | ping | OK | + +--- + +## SSH + +| User | Command | +|------|---------| +| root | `ssh root@10.100.1.26` atau alias `ssh ollama` | +| geonet | `ssh geonet@10.100.1.26` | + +Script helper: `server-connection/scripts/ssh-ollama.ps1` + +> SSH oleh agent wajib persetujuan user. + +--- + +## Endpoint + +| Env | URL | Env var (consumer) | +|-----|-----|-------------------| +| prod (VLAN) | `http://10.100.1.26:11434` | `OLLAMA_BASE_URL` | + +Consumer: `server-connection/geonet-console` di `10.100.1.24`. + +**Tidak** ada reverse proxy publik — by design ([ADR-0001](./adr/ADR-0001-dedicated-ollama-vm.md)). + +--- + +## Mapping ke monorepo + +| Komponen | Path | +|----------|------| +| Dokumentasi Ollama | `Ollama/` | +| Config consumer | `server-connection/geonet-console/config/ollama.php` | +| Requirement indexer | `server-connection/server/ollama-nas-project-search-requirements.md` | +| SSH script | `server-connection/scripts/ssh-ollama.ps1` | + +--- + +## Dependency + +| Service | Host | Relasi | +|---------|------|--------| +| geonet-console | `.24` | HTTP client Ollama API | +| PostgreSQL + pgvector | `.25` | Vector store (planned) | +| QNAP NAS | `.10` | SMB source indexer (planned) | + +--- + +## Instalasi (referensi) + +Ollama diinstall native (bukan Docker), ~2026-06-15: + +```bash +curl -fsSL https://ollama.com/install.sh | sh +mkdir -p /data/ollama/models && chown ollama:ollama /data/ollama/models +ollama pull nomic-embed-text +ollama pull qwen2.5:7b +systemctl enable --now ollama +``` + +Verifikasi: + +```bash +curl -s http://127.0.0.1:11434/api/version +ollama list +``` diff --git a/Ollama/docs/system-requirements.md b/Ollama/docs/system-requirements.md new file mode 100644 index 0000000..b8f188f --- /dev/null +++ b/Ollama/docs/system-requirements.md @@ -0,0 +1,86 @@ +# System Requirements — Ollama + +**Project:** `Ollama/` +**Tipe:** infra (AI inference) +**Last updated:** 2026-07-06 + +--- + +## Ringkasan + +Ollama native di Ubuntu LTS — **tanpa Docker**. Inference CPU (tanpa GPU wajib). + +--- + +## Platform & OS + +| Komponen | Minimum | Direkomendasikan | Saat ini (`.26`) | +|----------|---------|------------------|------------------| +| OS server | Ubuntu 22.04 LTS | Ubuntu **Server** 22.04 | 22.04.5 Desktop ⚠️ | +| Arsitektur | x86_64 + AVX2 | x86_64 | ✅ AVX2 | +| vCPU | 16 | 16–48 | ✅ 48 | +| RAM | 32 GiB | 64 GiB | ✅ 62 GiB | +| Disk model | 50 GB free | ≥ 100 GB di `/data/ollama` | ✅ 457 GB free | + +--- + +## Runtime & Toolchain + +| Tool | Versi | Cek | +|------|-------|-----| +| Ollama | 0.30.8+ | `ollama --version` | +| systemd | — | `systemctl status ollama` | +| ufw | — | `ufw status` | +| curl | — | smoke test API | + +**Tidak dipakai:** Docker, GPU driver, nginx di host ini. + +--- + +## Model (production CPU) + +| Model | Peran | RAM load (approx) | +|-------|-------|-------------------| +| `qwen2.5:7b` | Chat / answer | ~5–8 GB | +| `nomic-embed-text` | Embedding | ~1 GB | + +--- + +## Dependency eksternal + +| Dependency | Host | Dipakai untuk | Owner docs | +|------------|------|---------------|------------| +| PostgreSQL + pgvector | `10.100.1.25` | Vector index | server-connection | +| QNAP SMB | `10.100.1.10` | Indexer source | server-connection | +| geonet-console | `10.100.1.24` | API consumer | server-connection | + +--- + +## Variabel URL & konfigurasi + +Dari [.env.example](../.env.example): + +| Variabel | Contoh | Keterangan | +|----------|--------|------------| +| `OLLAMA_BASE_URL` | `http://10.100.1.26:11434` | Base URL API (consumer) | +| `OLLAMA_CHAT_MODEL` | `qwen2.5:7b` | Model chat | +| `OLLAMA_EMBED_MODEL` | `nomic-embed-text` | Model embedding | +| `OLLAMA_TIMEOUT` | `120` | Timeout detik (HTTP client) | + +Server-side (systemd, **bukan** di repo): + +| Variabel | Nilai live | +|----------|------------| +| `OLLAMA_HOST` | `0.0.0.0:11434` | +| `OLLAMA_MODELS` | `/data/ollama/models` | +| `OLLAMA_NUM_PARALLEL` | `2` | +| `OLLAMA_MAX_LOADED_MODELS` | `2` | + +**Aturan:** no hardcode URL/IP di kode aplikasi — gunakan env. + +--- + +## Network + +- Ollama API hanya dari subnet `10.100.1.0/24` +- Tidak perlu TLS internal (VLAN trusted); TLS di edge app jika perlu diff --git a/Ollama/docs/todo.md b/Ollama/docs/todo.md new file mode 100644 index 0000000..81fa8b3 --- /dev/null +++ b/Ollama/docs/todo.md @@ -0,0 +1,68 @@ +# TODO — Ollama + +> Last updated: 2026-07-06 + +--- + +## High Priority + +### Fase 1 — GPU Node (PC-Multimedia) ✅ SELESAI +- [x] CUDA 12.9 sudah tersedia via driver 576.88 (tidak perlu install terpisah) +- [x] Install Ollama v0.31.1 di Windows (`OllamaSetup.exe`) +- [x] Set `OLLAMA_MODELS=T:\ollama\models` + `OLLAMA_HOST=0.0.0.0:11434` via `setx /M` +- [x] Autostart via Task Scheduler (SYSTEM, AtStartup) — script `PC-Multimedia/scripts/install-ollama-task.ps1` +- [x] Firewall rule `OllamaVLAN`: TCP 11434 dari `10.100.1.0/24` only +- [x] Pull `qwen2.5-coder:14b` (9.0 GB) + `nomic-embed-text` (274 MB) → `T:\ollama\models` +- [x] Verified: API `http://10.100.1.14:11434` reachable, VRAM 11.5 GB / 16 GB saat loaded + +### Fase 2 — pgvector + Codebase Index ✅ SELESAI +- [x] pgvector Docker di `10.100.1.24:5433` (pgvector 0.8.4 / pg16) +- [x] DB `geonet_project_search` + tabel `code_chunks` + `user_memory` + index HNSW +- [x] Script indexer `Ollama/indexer/indexer.py` — 1.784 chunks dari 1.031 files, 18 repo +- [x] Verified: similarity search akurat (query → FeedbackController.php sebagai top result) + +### Fase 3 — Integrasi geonet-console ✅ SELESAI +- [x] `OLLAMA_BASE_URL=http://10.100.1.14:11434` di geonet-console `.env` +- [x] `AiChatService` — embed query → pgvector similarity search → inject context → Ollama chat +- [x] `AiChatController` — `POST /api/v1/ai/chat` + `GET /api/v1/ai/status` +- [x] `config/pgvector.php` — config PGVECTOR_HOST/PORT/DB/USER/PASS +- [x] Verified end-to-end: 5 context chunks retrieved, jawaban akurat tentang route feedback +- [ ] User memory: simpan pola interaksi per user (next iteration) + +### VM .26 (tetap jalan sebagai fallback) +- [ ] Tetap running `qwen2.5:7b` + `nomic-embed-text` sebagai fallback CPU inference +- [ ] SMB read-only mount QNAP `10.100.1.10` di VM `.26` (indexer background) + +--- + +## Medium Priority + +- [ ] UI chat di Super Apps PWA — window chat terintegrasi +- [ ] User memory / RAG: retrieve pola kebiasaan user saat generate response +- [ ] Deploy agent (Fase 4): tool calling SSH + docker exec untuk bantu deploy +- [ ] Healthcheck / monitoring (Zabbix atau cron `ollama ps`) +- [ ] Optimasi VM `.26`: Ubuntu Desktop → Server atau matikan GUI (hemat RAM) + +--- + +## Low Priority + +- [ ] Fine-tuning LoRA untuk template spesifik organisasi (butuh 1000+ contoh data) +- [ ] Evaluasi model `deepseek-coder-v2:16b` untuk coding tasks +- [ ] Backup `/data/ollama/models` ke QNAP +- [ ] Dokumentasi troubleshooting inference timeout +- [ ] Migrasi model ke VM `.26` jika PC-Multimedia tidak bisa 24/7 + +--- + +## Selesai (Sesi Ini) + +- [x] Audit live VM `10.100.1.26` — Ollama + model verified +- [x] Bootstrap dokumentasi repo `Ollama/` (AI-Agent-Standards) +- [x] Daftar di `Workspace-Context.md` +- [x] Audit hardware PC-Multimedia via DxDiag — Core Ultra 7 265K, 64 GB, RTX 5060 Ti +- [x] Diskusi arsitektur AI onprem: Context Injection → RAG/Memory → Fine-tuning +- [x] Diskusi AI coding assistant + deploy agent on-premise +- [x] **Fase 1 GPU Node PC-Multimedia** — Ollama v0.31.1, GPU inference aktif, verified dari laptop +- [x] **Fase 2 pgvector** — Docker `10.100.1.24:5433`, 1.784 chunks, similarity search verified +- [x] **Fase 3 integrasi** — `POST /api/v1/ai/chat` live, RAG end-to-end verified di geonet-console diff --git a/Ollama/docs/version.md b/Ollama/docs/version.md new file mode 100644 index 0000000..0390c98 --- /dev/null +++ b/Ollama/docs/version.md @@ -0,0 +1,37 @@ +# Version History + +**Owner:** riwayat versi deploy/config Ollama VM — append per perubahan material. +Sinkron dengan [changelog.md](./changelog.md). + +--- + +## [0.1.0] - 2026-07-06 + +- Bootstrap dokumentasi repo `Ollama/` (AI-Agent-Standards) +- Audit live VM `aiopr` (`10.100.1.26`): + - Ollama **0.30.8**, systemd enabled/active + - `OLLAMA_HOST=0.0.0.0:11434`, `OLLAMA_MODELS=/data/ollama/models` + - Models: `qwen2.5:7b`, `nomic-embed-text:latest` + - UFW: `11434/tcp` allow `10.100.1.0/24` + - 48 vCPU Xeon E5-2699 v4, 62 GiB RAM, 503 GB disk (~457 GB free) +- Consumer geonet-console & indexer: **belum** diaktifkan + +--- + +## [0.2.0] - 2026-07-06 + +- PC-Multimedia `10.100.1.14`: Ollama v0.31.1 GPU install +- Models: `qwen2.5-coder:14b` (9 GB) + `nomic-embed-text` (274 MB) di `T:\ollama\models` +- Autostart Task Scheduler SYSTEM, Firewall VLAN-only TCP 11434 +- Verified: VRAM 11.5 GB / 16 GB aktif + +--- + +## [0.4.0] - 2026-07-06 + +- pgvector Docker `10.100.1.24:5433`, DB `geonet_project_search`, user `geonet_ai` +- Indexer Python: 1.784 chunks dari 1.031 files, 18 repo, chunk 80 baris +- geonet-console: `POST /api/v1/ai/chat` + `GET /api/v1/ai/status` live +- `AiChatService`: embed → pgvector similarity search → Ollama chat +- `OLLAMA_BASE_URL=http://10.100.1.14:11434`, model `qwen2.5-coder:14b` +- Verified end-to-end: 5 chunks retrieved, jawaban akurat diff --git a/Ollama/indexer/.env.example b/Ollama/indexer/.env.example new file mode 100644 index 0000000..b806c0c --- /dev/null +++ b/Ollama/indexer/.env.example @@ -0,0 +1,12 @@ +PGVECTOR_HOST=10.100.1.24 +PGVECTOR_PORT=5433 +PGVECTOR_DB=geonet_project_search +PGVECTOR_USER=geonet_ai +PGVECTOR_PASSWORD=changeme + +OLLAMA_HOST=http://10.100.1.14:11434 +EMBED_MODEL=nomic-embed-text + +REPO_ROOT=D:\Project\app on git +CHUNK_SIZE=400 +CHUNK_OVERLAP=50 diff --git a/Ollama/indexer/indexer.py b/Ollama/indexer/indexer.py new file mode 100644 index 0000000..df5895b --- /dev/null +++ b/Ollama/indexer/indexer.py @@ -0,0 +1,199 @@ +""" +Codebase Indexer untuk AI Search (Fase 2) +Crawl monorepo → chunk → embed via Ollama nomic-embed-text → simpan ke pgvector +""" + +import os +import sys +import hashlib +import json +import time +import requests +import psycopg +from pathlib import Path +from dotenv import load_dotenv + +load_dotenv() + +PGVECTOR_HOST = os.getenv("PGVECTOR_HOST", "10.100.1.24") +PGVECTOR_PORT = int(os.getenv("PGVECTOR_PORT", "5433")) +PGVECTOR_DB = os.getenv("PGVECTOR_DB", "geonet_project_search") +PGVECTOR_USER = os.getenv("PGVECTOR_USER", "geonet_ai") +PGVECTOR_PASS = os.getenv("PGVECTOR_PASSWORD", "") +OLLAMA_HOST = os.getenv("OLLAMA_HOST", "http://10.100.1.14:11434") +EMBED_MODEL = os.getenv("EMBED_MODEL", "nomic-embed-text") +REPO_ROOT = Path(os.getenv("REPO_ROOT", r"D:\Project\app on git")) +CHUNK_SIZE = int(os.getenv("CHUNK_SIZE", "400")) +CHUNK_OVERLAP = int(os.getenv("CHUNK_OVERLAP", "50")) + +INCLUDE_EXTENSIONS = { + ".php", ".ts", ".tsx", ".js", ".py", + ".md", ".yaml", ".yml", ".sql", ".env.example", + ".json", +} + +EXCLUDE_DIRS = { + "node_modules", "vendor", ".git", ".next", "__pycache__", + "dist", "build", ".idea", ".vscode", "storage/logs", + ".venv", "venv", "env", ".env", +} + +EXCLUDE_FILES = { + "package-lock.json", "composer.lock", "yarn.lock", +} + +LANGUAGE_MAP = { + ".php": "php", ".ts": "typescript", ".tsx": "tsx", + ".js": "javascript", ".py": "python", ".md": "markdown", + ".yaml": "yaml", ".yml": "yaml", ".sql": "sql", + ".json": "json", +} + + +def get_repo_name(file_path: Path) -> str: + try: + rel = file_path.relative_to(REPO_ROOT) + parts = rel.parts + return parts[0] if len(parts) > 1 else "root" + except ValueError: + return "unknown" + + +def chunk_text(text: str, size: int = CHUNK_SIZE, overlap: int = CHUNK_OVERLAP): + """Split teks jadi chunk berdasarkan baris, bukan token.""" + lines = text.splitlines(keepends=True) + chunks = [] + current, current_lines, start_line = [], 0, 1 + + for i, line in enumerate(lines, start=1): + current.append(line) + current_lines += 1 + if current_lines >= size: + chunks.append(("".join(current), start_line, i)) + keep = max(0, len(current) - overlap) + current = current[keep:] + start_line = i - len(current) + 1 + current_lines = len(current) + + if current: + chunks.append(("".join(current), start_line, start_line + len(current) - 1)) + + return chunks + + +def get_embedding(text: str, retries: int = 3) -> list[float] | None: + for attempt in range(retries): + try: + resp = requests.post( + f"{OLLAMA_HOST}/api/embeddings", + json={"model": EMBED_MODEL, "prompt": text}, + timeout=60, + ) + resp.raise_for_status() + return resp.json().get("embedding") + except Exception as e: + if attempt < retries - 1: + time.sleep(2 ** attempt) # exponential backoff: 1s, 2s + else: + print(f" [EMBED ERROR] {e}") + return None + + +def collect_files() -> list[Path]: + files = [] + for path in REPO_ROOT.rglob("*"): + if not path.is_file(): + continue + if any(ex in path.parts for ex in EXCLUDE_DIRS): + continue + if path.name in EXCLUDE_FILES: + continue + if path.suffix.lower() not in INCLUDE_EXTENSIONS: + continue + files.append(path) + return sorted(files) + + +def file_checksum(path: Path) -> str: + return hashlib.md5(path.read_bytes()).hexdigest() + + +def index_files(conn, files: list[Path]): + cur = conn.cursor() + + cur.execute("SELECT file_path, checksum FROM code_chunks GROUP BY file_path, checksum") + indexed = {row[0]: row[1] for row in cur.fetchall()} + + total = len(files) + skipped = inserted = errors = 0 + + for i, fpath in enumerate(files, 1): + rel_path = str(fpath.relative_to(REPO_ROOT)).replace("\\", "/") + checksum = file_checksum(fpath) + + if indexed.get(rel_path) == checksum: + skipped += 1 + continue + + try: + text = fpath.read_text(encoding="utf-8", errors="ignore") + except Exception as e: + print(f" [READ ERROR] {rel_path}: {e}") + errors += 1 + continue + + if not text.strip(): + skipped += 1 + continue + + chunks = chunk_text(text) + lang = LANGUAGE_MAP.get(fpath.suffix.lower(), "text") + repo = get_repo_name(fpath) + + if rel_path in indexed: + cur.execute("DELETE FROM code_chunks WHERE file_path = %s", (rel_path,)) + + chunk_ok = 0 + for content, start, end in chunks: + content = content.replace("\x00", "") + if not content.strip(): + continue + embedding = get_embedding(content) + if embedding is None: + continue + cur.execute( + """ + INSERT INTO code_chunks (repo, file_path, language, start_line, end_line, content, embedding, checksum) + VALUES (%s, %s, %s, %s, %s, %s, %s::vector, %s) + """, + (repo, rel_path, lang, start, end, content, json.dumps(embedding), checksum), + ) + chunk_ok += 1 + + conn.commit() + inserted += chunk_ok + + print(f"[{i}/{total}] {rel_path} → {chunk_ok} chunks", flush=True) + + cur.close() + print(f"\n✅ Selesai: {inserted} chunks inserted, {skipped} files skipped, {errors} errors") + + +def main(): + print(f"Connecting to pgvector {PGVECTOR_HOST}:{PGVECTOR_PORT}...") + conn = psycopg.connect( + host=PGVECTOR_HOST, port=PGVECTOR_PORT, dbname=PGVECTOR_DB, + user=PGVECTOR_USER, password=PGVECTOR_PASS, + ) + print(f"Repo root: {REPO_ROOT}") + print(f"Ollama embed: {OLLAMA_HOST} model={EMBED_MODEL}") + + files = collect_files() + print(f"Files to index: {len(files)}") + + index_files(conn, files) + conn.close() + + +if __name__ == "__main__": + main() diff --git a/Ollama/indexer/requirements.txt b/Ollama/indexer/requirements.txt new file mode 100644 index 0000000..e66d470 --- /dev/null +++ b/Ollama/indexer/requirements.txt @@ -0,0 +1,3 @@ +psycopg[binary]==3.2.3 +requests==2.31.0 +python-dotenv==1.0.0 diff --git a/Ollama/scripts/gc-aitest.sh b/Ollama/scripts/gc-aitest.sh new file mode 100644 index 0000000..1bf8a08 --- /dev/null +++ b/Ollama/scripts/gc-aitest.sh @@ -0,0 +1,21 @@ +#!/bin/bash +echo "=== Login ===" +RESP=$(curl -sk -X POST https://console.gisportal.id/api/v1/auth/login \ + -H 'Content-Type: application/json' \ + -d '{"username":"rbsetiawan","password":"Rifqi123"}') +echo "$RESP" | python3 -m json.tool 2>/dev/null | head -5 + +TOKEN=$(echo "$RESP" | python3 -c 'import sys,json; d=json.load(sys.stdin); print(d.get("data",{}).get("token",""))' 2>/dev/null) +echo "Token: ${TOKEN:0:30}..." + +echo "" +echo "=== GET /api/v1/ai/status ===" +curl -sk https://console.gisportal.id/api/v1/ai/status \ + -H "Authorization: Bearer $TOKEN" | python3 -m json.tool + +echo "" +echo "=== POST /api/v1/ai/chat ===" +curl -sk -X POST https://console.gisportal.id/api/v1/ai/chat \ + -H "Authorization: Bearer $TOKEN" \ + -H 'Content-Type: application/json' \ + -d '{"message":"di mana route untuk feedback di geonet-console?"}' | python3 -m json.tool diff --git a/Ollama/scripts/gc-aitest2.sh b/Ollama/scripts/gc-aitest2.sh new file mode 100644 index 0000000..d71f19e --- /dev/null +++ b/Ollama/scripts/gc-aitest2.sh @@ -0,0 +1,23 @@ +#!/bin/bash +cd /var/www/html +php artisan tinker --execute " +// Simulasi request langsung ke AiChatController +\$service = app(App\Services\AiChatService::class); +echo 'AiChatService available: ' . (\$service->isAvailable() ? 'YES' : 'NO') . PHP_EOL; +echo 'OLLAMA_BASE_URL: ' . config('ollama.base_url') . PHP_EOL; +echo 'OLLAMA_CHAT_MODEL: ' . config('ollama.chat_model') . PHP_EOL; +echo 'PGVECTOR_HOST: ' . config('pgvector.host') . PHP_EOL; +echo PHP_EOL; + +// Test chat +echo 'Testing chat...' . PHP_EOL; +\$result = \$service->chat( + query: 'di mana route untuk feedback di geonet-console?', + username: 'rbsetiawan', + displayName: 'Rifqi', + jobTitle: 'IT Admin', + history: [] +); +echo 'Context chunks: ' . \$result['meta']['context_count'] . PHP_EOL; +echo 'Answer: ' . PHP_EOL . \$result['answer'] . PHP_EOL; +" 2>&1 | grep -v "Deprecated\|trim()" diff --git a/Ollama/scripts/gc-boot.sh b/Ollama/scripts/gc-boot.sh new file mode 100644 index 0000000..24f5279 --- /dev/null +++ b/Ollama/scripts/gc-boot.sh @@ -0,0 +1,5 @@ +#!/bin/bash +cd /var/www/html +echo "APP_KEY length: ${#APP_KEY}" +echo "Testing artisan with verbose..." +php artisan package:discover --ansi -v 2>&1 | head -30 diff --git a/Ollama/scripts/gc-clearcache.sh b/Ollama/scripts/gc-clearcache.sh new file mode 100644 index 0000000..da63565 --- /dev/null +++ b/Ollama/scripts/gc-clearcache.sh @@ -0,0 +1,7 @@ +#!/bin/bash +cd /var/www/html +echo "=== clearing bootstrap cache ===" +rm -f bootstrap/cache/packages.php bootstrap/cache/services.php bootstrap/cache/config.php bootstrap/cache/routes-v7.php +echo "=== re-discover ===" +php artisan package:discover --ansi 2>&1 +echo "EXIT: $?" diff --git a/Ollama/scripts/gc-debug.sh b/Ollama/scripts/gc-debug.sh new file mode 100644 index 0000000..d33a838 --- /dev/null +++ b/Ollama/scripts/gc-debug.sh @@ -0,0 +1,11 @@ +#!/bin/bash +cd /var/www/html +echo "APP_KEY=${APP_KEY:0:20}..." +echo "APP_ENV=$APP_ENV" +echo "---" +php -r " +\$app = require_once __DIR__.'/bootstrap/app.php'; +\$app->bootstrapWith([\Illuminate\Foundation\Bootstrap\LoadEnvironmentVariables::class, \Illuminate\Foundation\Bootstrap\LoadConfiguration::class]); +echo 'APP_KEY loaded: '.strlen(config('app.key')).' chars'.PHP_EOL; +echo 'APP_ENV: '.config('app.env').PHP_EOL; +" 2>&1 diff --git a/Ollama/scripts/gc-facade.sh b/Ollama/scripts/gc-facade.sh new file mode 100644 index 0000000..fab04f8 --- /dev/null +++ b/Ollama/scripts/gc-facade.sh @@ -0,0 +1,7 @@ +#!/bin/bash +cd /var/www/html +echo "=== Facade.php line 355-365 ===" +sed -n '355,365p' vendor/laravel/framework/src/Illuminate/Support/Facades/Facade.php +echo "" +echo "=== artisan with strace first lines ===" +php artisan list 2>&1 | grep -v Deprecated | head -5 diff --git a/Ollama/scripts/gc-fulltest.sh b/Ollama/scripts/gc-fulltest.sh new file mode 100644 index 0000000..75fb890 --- /dev/null +++ b/Ollama/scripts/gc-fulltest.sh @@ -0,0 +1,18 @@ +#!/bin/bash +cd /var/www/html +echo "=== PHP version ===" +php --version | head -1 + +echo "=== Load vendor + boot Laravel ===" +php -r " +require '/var/www/html/vendor/autoload.php'; +\$app = require_once '/var/www/html/bootstrap/app.php'; +echo 'App version: '.\$app->version().PHP_EOL; +echo 'App booted: '.(\$app->isBooted() ? 'yes' : 'no').PHP_EOL; +\$kernel = \$app->make(Illuminate\Contracts\Console\Kernel::class); +\$kernel->bootstrap(); +echo 'Kernel bootstrapped OK'.PHP_EOL; +" 2>&1 + +echo "=== artisan route:list --path=ai ===" +php artisan route:list --path=ai 2>&1 | grep -v Deprecated diff --git a/Ollama/scripts/gc-gettoken.sh b/Ollama/scripts/gc-gettoken.sh new file mode 100644 index 0000000..b2c1972 --- /dev/null +++ b/Ollama/scripts/gc-gettoken.sh @@ -0,0 +1,11 @@ +#!/bin/bash +cd /var/www/html +php artisan tinker --execute " +\$token = App\Models\ApiToken::whereNull('revoked_at')->latest()->first(); +if (\$token) { + echo 'token=' . \$token->token . PHP_EOL; + echo 'owner=' . \$token->owner_identifier . PHP_EOL; +} else { + echo 'no active token found' . PHP_EOL; +} +" 2>&1 | grep -v Deprecated diff --git a/Ollama/scripts/gc-gettoken2.sh b/Ollama/scripts/gc-gettoken2.sh new file mode 100644 index 0000000..65951e1 --- /dev/null +++ b/Ollama/scripts/gc-gettoken2.sh @@ -0,0 +1,10 @@ +#!/bin/bash +cd /var/www/html +php artisan tinker --execute " +\$row = DB::table('api_tokens')->latest()->first(); +if (\$row) { + echo json_encode((array)\$row, JSON_PRETTY_PRINT) . PHP_EOL; +} else { + echo 'no token' . PHP_EOL; +} +" 2>&1 | grep -v Deprecated diff --git a/Ollama/scripts/gc-maketoken.sh b/Ollama/scripts/gc-maketoken.sh new file mode 100644 index 0000000..f392eba --- /dev/null +++ b/Ollama/scripts/gc-maketoken.sh @@ -0,0 +1,12 @@ +#!/bin/bash +cd /var/www/html +php artisan tinker --execute " +\$token = App\Models\ApiToken::create([ + 'name' => 'ai-test-token', + 'token' => 'ai-test-' . bin2hex(random_bytes(16)), + 'owner_type' => 'user', + 'owner_identifier' => 'rbsetiawan', + 'scopes' => json_encode(['admin']), +]); +echo 'TOKEN=' . \$token->token . PHP_EOL; +" 2>&1 | grep -v Deprecated | grep TOKEN diff --git a/Ollama/scripts/gc-syntax.sh b/Ollama/scripts/gc-syntax.sh new file mode 100644 index 0000000..7dcbdbe --- /dev/null +++ b/Ollama/scripts/gc-syntax.sh @@ -0,0 +1,10 @@ +#!/bin/bash +cd /var/www/html +echo "=== PHP syntax check new files ===" +php -l app/Services/AiChatService.php +php -l app/Http/Controllers/Api/V1/AiChatController.php +php -l config/pgvector.php +php -l config/ollama.php +php -l routes/api.php +echo "=== artisan package:discover ===" +php artisan package:discover --ansi 2>&1 diff --git a/Ollama/scripts/gc-vendor.sh b/Ollama/scripts/gc-vendor.sh new file mode 100644 index 0000000..11a8cdb --- /dev/null +++ b/Ollama/scripts/gc-vendor.sh @@ -0,0 +1,8 @@ +#!/bin/bash +cd /var/www/html +echo "=== vendor check ===" +php -r "require_once '/var/www/html/vendor/autoload.php'; echo class_exists('Illuminate\Foundation\Application') ? 'Application: OK' : 'Application: MISSING'; echo PHP_EOL;" +echo "=== providers ===" +cat /var/www/html/bootstrap/providers.php +echo "=== artisan strict ===" +php -d display_errors=1 -d error_reporting=E_ALL artisan about 2>&1 | grep -v Deprecated | head -20 diff --git a/PC-Multimedia/.env.example b/PC-Multimedia/.env.example new file mode 100644 index 0000000..00617ed --- /dev/null +++ b/PC-Multimedia/.env.example @@ -0,0 +1,22 @@ +# PC-Multimedia — template konfigurasi (AMAN di-commit) +# Copy ke .env lokal (JANGAN commit .env) + +# --- Host identity --- +HOSTNAME=MULTIMEDIA +HOST_IP_PRIMARY=10.100.1.14 +HOST_IP_SECONDARY=192.168.0.18 + +# --- SSH (dari laptop dev) --- +SSH_USER=admin +SSH_PORT=22 +SSH_ALIAS=multimedia +# Key laptop: ~/.ssh/id_ed25519_geonet_proxmox + +# --- Network --- +GATEWAY_PRIMARY=10.100.1.1 +GATEWAY_SECONDARY=192.168.0.1 +SUBNET_PRIMARY=10.100.1.0/24 +SUBNET_SECONDARY=192.168.0.0/24 + +# Dokumentasi: docs/server.md, docs/system-requirements.md +# Migrasi IP: docs/guide/migration.md diff --git a/PC-Multimedia/AGENTS.md b/PC-Multimedia/AGENTS.md new file mode 100644 index 0000000..f5d8dff --- /dev/null +++ b/PC-Multimedia/AGENTS.md @@ -0,0 +1,44 @@ +# AGENTS.md — Cold Start + +> Project: `PC-Multimedia/` +> Sesi: [docs/ai-session-summary.md](./docs/ai-session-summary.md) +> Peta: [docs/context-index.md](./docs/context-index.md) +> Env: [.env.example](./.env.example) + +## Apa ini? + +Workstation **MULTIMEDIA** (Windows 10 Pro) — PC dev/GIS dengan dual NIC dan OpenSSH Server untuk akses remote dari laptop infrastruktur (passwordless key). + +## Aturan kritis + +- User `admin` (Administrators) → public key **wajib** di `C:\ProgramData\ssh\administrators_authorized_keys`, **bukan** `~/.ssh/authorized_keys` +- SSH dari LAN server: `ssh multimedia` → `10.100.1.14`; dari LAN MikroTik: `ssh admin@192.168.0.18` +- Key laptop: `~/.ssh/id_ed25519_geonet_proxmox` (alias `multimedia` di `~/.ssh/config`) +- **No hardcoded IP** di skrip — baca `.env` / env var / ssh alias +- Jangan commit `.env` atau password admin +- No commit kecuali user minta eksplisit +- Pengetahuan penting wajib ke docs, bukan hanya chat + +## Lanjut kerja + +``` +1. AGENTS.md <- Anda di sini +2. docs/ai-session-summary.md <- TL;DR + Lanjut + Jangan +3. STOP - mulai kerja +4. On-demand: docs/server.md, docs/todo.md, docs/guide/migration.md +``` + +## Pointer cepat + +| Butuh | Buka | +|-------|------| +| Host / IP / SSH | [docs/server.md](./docs/server.md) | +| Setup key ulang | [../server-audit/scripts/setup-ssh-key-multimedia.ps1](../server-audit/scripts/setup-ssh-key-multimedia.ps1) | +| SSH index lintas host | [../server-audit/host.md](../server-audit/host.md) | +| Migrasi IP/domain | [docs/guide/migration.md](./docs/guide/migration.md) | +| Priority | [docs/todo.md](./docs/todo.md) | +| Versi | [docs/version.md](./docs/version.md) | + +## Multi-project + +`Workspace-Context.md` → `PC-Multimedia/AGENTS.md` → `docs/ai-session-summary.md` diff --git a/PC-Multimedia/DxDiag.txt b/PC-Multimedia/DxDiag.txt new file mode 100644 index 0000000..f0fff4e --- /dev/null +++ b/PC-Multimedia/DxDiag.txt @@ -0,0 +1,1372 @@ +------------------ +System Information +------------------ + Time of this report: 7/6/2026, 16:15:15 + Machine name: MULTIMEDIA + Machine Id: {D1B5F522-AA34-4393-AAF7-E52E8A5DDE5A} + Operating System: Windows 10 Pro 64-bit (10.0, Build 19045) (19041.vb_release.191206-1406) + Language: Indonesian (Regional Setting: Indonesian) + System Manufacturer: Gigabyte Technology Co., Ltd. + System Model: Z890 AERO G + BIOS: F9 (type: UEFI) + Processor: Intel(R) Core(TM) Ultra 7 265K (20 CPUs), ~3.9GHz + Memory: 65536MB RAM + Available OS Memory: 65238MB RAM + Page File: 12699MB used, 56634MB available + Windows Dir: C:\Windows + DirectX Version: DirectX 12 + DX Setup Parameters: Not found + User DPI Setting: 96 DPI (100 percent) + System DPI Setting: 96 DPI (100 percent) + DWM DPI Scaling: Disabled + Miracast: Available, no HDCP +Microsoft Graphics Hybrid: Not Supported + DirectX Database Version: 1.0.8 + DxDiag Version: 10.00.19041.5794 64bit Unicode + +------------ +DxDiag Notes +------------ + Display Tab 1: No problems found. + Display Tab 2: No problems found. + Sound Tab 1: No problems found. + Input Tab: No problems found. + +-------------------- +DirectX Debug Levels +-------------------- +Direct3D: 0/4 (retail) +DirectDraw: 0/4 (retail) +DirectInput: 0/5 (retail) +DirectMusic: 0/5 (retail) +DirectPlay: 0/9 (retail) +DirectSound: 0/5 (retail) +DirectShow: 0/6 (retail) + +--------------- +Display Devices +--------------- + Card name: Microsoft Remote Display Adapter + Manufacturer: Microsoft + Chip type: Unknown + DAC type: Unknown + Device Type: Display-Only Device + Device Key: Enum\SWD\REMOTEDISPLAYENUM + Device Status: 0180600A [DN_DRIVER_LOADED|DN_STARTED|DN_DISABLEABLE|DN_REMOVABLE|DN_NT_ENUMERATOR|DN_NT_DRIVER] + Device Problem Code: No Problem + Driver Problem Code: Unknown + Display Memory: 53147 MB + Dedicated Memory: 15962 MB + Shared Memory: 37185 MB + Current Mode: 1920 x 1080 (32 bit) (32Hz) + HDR Support: Not Supported + Display Topology: Internal + Display Color Space: DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709 + Color Primaries: Red(0.000000,0.000000), Green(0.000000,0.000000), Blue(0.000000,0.000000), White Point(0.000000,0.000000) + Display Luminance: Min Luminance = 0.000000, Max Luminance = 0.000000, MaxFullFrameLuminance = 0.000000 + Monitor Name: Generic Non-PnP Monitor + Monitor Model: unknown + Monitor Id: + Native Mode: unknown + Output Type: Unknown +Monitor Capabilities: HDR Not Supported +Display Pixel Format: DISPLAYCONFIG_PIXELFORMAT_32BPP + Advanced Color: Not Supported + Driver Name: c:\windows\system32\drivers\umdf\rdpidd.dll,c:\windows\system32\drivers\wudfrd.sys + Driver File Version: 10.00.19041.5794 (Indonesian) + Driver Version: 10.0.19041.5794 + DDI Version: 12 + Feature Levels: 12_1,12_0,11_1,11_0,10_1,10_0,9_3,9_2,9_1 + Driver Model: WDDM 1.3 + Hardware Scheduling: Supported:True Enabled:False + Graphics Preemption: DMA + Compute Preemption: DMA + Miracast: Not Supported by Graphics driver + Detachable GPU: No + Hybrid Graphics GPU: Not Supported + Power P-states: Not Supported + Virtualization: Not Supported + Block List: No Blocks + Catalog Attributes: N/A + Driver Attributes: Final Retail + Driver Date/Size: 21/06/2006 07.00.00, 254464 bytes + WHQL Logo'd: Yes + WHQL Date Stamp: Unknown + Device Identifier: {D7B71E3E-6E44-11CF-DA69-5C730EC2ED35} + Vendor ID: 0x10DE + Device ID: 0x2D04 + SubSys ID: 0x53531462 + Revision ID: 0x00A1 + Driver Strong Name: rdpidd.inf:c14ce88470d6efe0:RdpIdd_Install.NT:10.0.19041.5794:RdpIdd_IndirectDisplay + Rank Of Driver: 00FF0000 + Video Accel: Unknown + DXVA2 Modes: {86695F12-340E-4F04-9FD3-9253DD327460} DXVA2_ModeMPEG2_VLD {6F3EC719-3735-42CC-8063-65CC3CB36616} DXVA2_ModeVC1_D2010 DXVA2_ModeVC1_VLD {32FCFE3F-DE46-4A49-861B-AC71110649D5} DXVA2_ModeH264_VLD_Stereo_Progressive_NoFGT DXVA2_ModeH264_VLD_Stereo_NoFGT DXVA2_ModeH264_VLD_NoFGT {0BAC4FE5-1532-4429-A854-F84DE0264422} DXVA2_ModeHEVC_VLD_Main DXVA2_ModeHEVC_VLD_Main10 {1A72925F-0C2C-4F15-96FB-B17D1473603F} {15DF9B21-06C4-47F1-841E-A67C97D7F312} {0BAC4FE5-1532-4429-A854-F84DE04953DB} {55BCAC81-F311-4093-A7D0-1CBC0B849BEE} {4008018F-F537-4B36-98CF-61AF8A2C1A33} {0DABEFFA-4458-4602-BC03-0795659D617C} {9798634D-FE9D-48E5-B4DA-DBEC45B3DF01} DXVA2_ModeMPEG4pt2_VLD_Simple DXVA2_ModeMPEG4pt2_VLD_AdvSimple_NoGMC {9947EC6F-689B-11DC-A320-0019DBBC4184} {33FCFE41-DE46-4A49-861B-AC71110649D5} DXVA2_ModeVP9_VLD_Profile0 DXVA2_ModeVP9_VLD_10bit_Profile2 {DDA19DC7-93B5-49F5-A9B3-2BDA28A2CE6E} {B8BE4CCB-CF53-46BA-8D59-D6B8A6DA5D2A} {6AFFD11E-1D96-42B1-A215-93A31F09A53D} {914C84A3-4078-4FA9-984C-E2F262CB5C9C} {8A1A1031-29BC-46D0-A007-E9B092CA6767} + Deinterlace Caps: n/a + D3D9 Overlay: Not Supported + DXVA-HD: Supported + DDraw Status: Not Available + D3D Status: Enabled + AGP Status: Not Available + MPO MaxPlanes: 0 + MPO Caps: Not Supported + MPO Stretch: Not Supported + MPO Media Hints: Not Supported + MPO Formats: Not Supported + PanelFitter Caps: Not Supported + PanelFitter Stretch: Not Supported + + Card name: NVIDIA GeForce RTX 5060 Ti + Manufacturer: NVIDIA + Chip type: NVIDIA GeForce RTX 5060 Ti + DAC type: Integrated RAMDAC + Device Type: Full Device (POST) + Device Key: Enum\PCI\VEN_10DE&DEV_2D04&SUBSYS_53531462&REV_A1 + Device Status: 0180200A [DN_DRIVER_LOADED|DN_STARTED|DN_DISABLEABLE|DN_NT_ENUMERATOR|DN_NT_DRIVER] + Device Problem Code: No Problem + Driver Problem Code: Unknown + Display Memory: Unknown + Dedicated Memory: n/a + Shared Memory: n/a + Current Mode: Unknown + HDR Support: Unknown + Display Topology: Unknown + Display Color Space: Unknown + Color Primaries: Unknown + Display Luminance: Unknown + Driver Name: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\nvldumdx.dll,C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\nvldumdx.dll,C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\nvldumdx.dll,C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\nvldumdx.dll + Driver File Version: 32.00.0015.7688 (English) + Driver Version: 32.0.15.7688 + DDI Version: unknown + Feature Levels: Unknown + Driver Model: WDDM 2.7 + Hardware Scheduling: Supported:True Enabled:False + Graphics Preemption: Pixel + Compute Preemption: Dispatch + Miracast: Not Supported by Graphics driver + Detachable GPU: No + Hybrid Graphics GPU: Not Supported + Power P-states: Not Supported + Virtualization: Paravirtualization + Block List: No Blocks + Catalog Attributes: Universal:False Declarative:True + Driver Attributes: Final Retail + Driver Date/Size: 24/06/2025 07.00.00, 810616 bytes + WHQL Logo'd: Yes + WHQL Date Stamp: Unknown + Device Identifier: Unknown + Vendor ID: 0x10DE + Device ID: 0x2D04 + SubSys ID: 0x53531462 + Revision ID: 0x00A1 + Driver Strong Name: oem20.inf:0f066de32eecb274:Section038:32.0.15.7688:pci\ven_10de&dev_2d04&subsys_53531462 + Rank Of Driver: 00CF0001 + Video Accel: Unknown + DXVA2 Modes: Unknown + Deinterlace Caps: n/a + D3D9 Overlay: Unknown + DXVA-HD: Unknown + DDraw Status: Enabled + D3D Status: Not Available + AGP Status: Enabled + MPO MaxPlanes: Unknown + MPO Caps: Unknown + MPO Stretch: Unknown + MPO Media Hints: Unknown + MPO Formats: Unknown + PanelFitter Caps: Unknown + PanelFitter Stretch: Unknown + +------------- +Sound Devices +------------- + Description: Remote Audio + Default Sound Playback: Yes + Default Voice Playback: Yes + Hardware ID: + Manufacturer ID: N/A + Product ID: N/A + Type: N/A + Driver Name: + Driver Version: + Driver Attributes: + WHQL Logo'd: + Date and Size: + Other Files: + Driver Provider: + HW Accel Level: Emulation Only + Cap Flags: 0xF1F + Min/Max Sample Rate: 100, 200000 +Static/Strm HW Mix Bufs: 1, 0 + Static/Strm HW 3D Bufs: 0, 0 + HW Memory: 0 + Voice Management: No + EAX(tm) 2.0 Listen/Src: No, No + I3DL2(tm) Listen/Src: No, No +Sensaura(tm) ZoomFX(tm): No + +--------------------- +Sound Capture Devices +--------------------- +--------------------- +Video Capture Devices +Number of Devices: 0 +--------------------- +------------------- +DirectInput Devices +------------------- + Device Name: Mouse + Attached: 1 + Controller ID: n/a +Vendor/Product ID: n/a + FF Driver: n/a + + Device Name: Keyboard + Attached: 1 + Controller ID: n/a +Vendor/Product ID: n/a + FF Driver: n/a + + Device Name: USB Keyboard + Attached: 1 + Controller ID: 0x0 +Vendor/Product ID: 0x046D, 0xC31C + FF Driver: n/a + + Device Name: USB Keyboard + Attached: 1 + Controller ID: 0x0 +Vendor/Product ID: 0x046D, 0xC31C + FF Driver: n/a + + Device Name: USB Keyboard + Attached: 1 + Controller ID: 0x0 +Vendor/Product ID: 0x046D, 0xC31C + FF Driver: n/a + + Device Name: GIGABYTE Device + Attached: 1 + Controller ID: 0x0 +Vendor/Product ID: 0x048D, 0x5711 + FF Driver: n/a + + Device Name: GIGABYTE Device + Attached: 1 + Controller ID: 0x0 +Vendor/Product ID: 0x048D, 0x5711 + FF Driver: n/a + +Poll w/ Interrupt: No + +----------- +USB Devices +----------- ++ USB Root Hub (USB 3.0) +| Vendor/Product ID: 0x8086, 0x7F6E +| Matching Device ID: USB\ROOT_HUB30 +| Service: USBHUB3 +| Driver: USBHUB3.SYS, 10/30/2025 10:14:43, 649600 bytes +| ++-+ Generic USB Hub +| | Vendor/Product ID: 0x05E3, 0x0608 +| | Location: Port_#0011.Hub_#0002 +| | Matching Device ID: USB\USB20_HUB +| | Service: USBHUB3 +| | Driver: USBHUB3.SYS, 10/30/2025 10:14:43, 649600 bytes +| | +| +-+ USB Composite Device +| | | Vendor/Product ID: 0x046D, 0xC31C +| | | Location: Port_#0001.Hub_#0003 +| | | Matching Device ID: USB\COMPOSITE +| | | Service: usbccgp +| | | Driver: usbccgp.sys, 10/30/2025 10:14:43, 191872 bytes +| | | +| | +-+ USB Input Device +| | | | Vendor/Product ID: 0x046D, 0xC31C +| | | | Location: 0080.0014.0000.011.001.000.000.000.000 +| | | | Matching Device ID: USB\Class_03&SubClass_01 +| | | | Service: HidUsb +| | | | Driver: hidusb.sys, 7/18/2025 19:36:24, 44032 bytes +| | | | Driver: hidclass.sys, 7/18/2025 19:36:24, 233472 bytes +| | | | Driver: hidparse.sys, 7/18/2025 19:36:24, 46080 bytes +| | | | +| | | +-+ HID Keyboard Device +| | | | | Vendor/Product ID: 0x046D, 0xC31C +| | | | | Matching Device ID: HID_DEVICE_SYSTEM_KEYBOARD +| | | | | Service: kbdhid +| | | | | Driver: kbdhid.sys, 12/7/2019 16:07:56, 46592 bytes +| | | | | Driver: kbdclass.sys, 12/7/2019 16:07:56, 71480 bytes +| | | +| +-+ USB Input Device +| | | Vendor/Product ID: 0x1A81, 0x2232 +| | | Location: Port_#0002.Hub_#0003 +| | | Matching Device ID: USB\Class_03&SubClass_01 +| | | Service: HidUsb +| | | Driver: hidusb.sys, 7/18/2025 19:36:24, 44032 bytes +| | | Driver: hidclass.sys, 7/18/2025 19:36:24, 233472 bytes +| | | Driver: hidparse.sys, 7/18/2025 19:36:24, 46080 bytes +| | | +| | +-+ HID-compliant mouse +| | | | Vendor/Product ID: 0x1A81, 0x2232 +| | | | Matching Device ID: HID_DEVICE_SYSTEM_MOUSE +| | | | Service: mouhid +| | | | Driver: mouhid.sys, 12/7/2019 16:07:56, 35328 bytes +| | | | Driver: mouclass.sys, 12/7/2019 16:07:56, 67600 bytes + +---------------- +Gameport Devices +---------------- + +------------ +PS/2 Devices +------------ ++ +| Service: MUTENX_SERVICE +| ++ Remote Desktop Keyboard Device +| Matching Device ID: TS_INPT\TS_KBD +| Service: terminpt +| Driver: terminpt.sys, 12/7/2019 16:07:56, 41272 bytes +| Driver: kbdclass.sys, 12/7/2019 16:07:56, 71480 bytes +| ++ +| Service: MUTENX_SERVICE +| ++ Remote Desktop Mouse Device +| Matching Device ID: TS_INPT\TS_MOU +| Service: terminpt +| Driver: terminpt.sys, 12/7/2019 16:07:56, 41272 bytes +| Driver: mouclass.sys, 12/7/2019 16:07:56, 67600 bytes + +------------------------ +Disk & DVD/CD-ROM Drives +------------------------ + Drive: C: + Free Space: 617.4 GB +Total Space: 1907.1 GB +File System: NTFS + Model: Samsung SSD 9100 PRO 2TB + + Drive: D: + Free Space: 96.0 GB +Total Space: 1907.7 GB +File System: NTFS + Model: ADATA LEGEND 860 + + Drive: T: + Free Space: 330.5 GB +Total Space: 1953.5 GB +File System: NTFS + Model: XPG GAMMIX S70 BLADE + +-------------- +System Devices +-------------- + Name: PCI Device +Device ID: PCI\VEN_8086&DEV_7F2F&SUBSYS_D0001458&REV_10\3&36CB97A3&0&A5 + Driver: n/a + + Name: PCI standard host CPU bridge +Device ID: PCI\VEN_8086&DEV_7D1B&SUBSYS_50001458&REV_01\3&11583659&0&00 + Driver: n/a + + Name: PCI Device +Device ID: PCI\VEN_8086&DEV_7F4C&SUBSYS_D0001458&REV_10\3&36CB97A3&0&A8 + Driver: n/a + + Name: PCI standard RAM Controller +Device ID: PCI\VEN_8086&DEV_AE7F&SUBSYS_D0001458&REV_10\3&11583659&0&A0 + Driver: n/a + + Name: PCI Express Root Port +Device ID: PCI\VEN_8086&DEV_7F38&SUBSYS_50011458&REV_10\3&36CB97A3&0&E0 + Driver: C:\Windows\system32\DRIVERS\pci.sys, 10.00.19041.6456 (English), 10/30/2025 10:14:43, 473488 bytes + + Name: PCI Express Root Port +Device ID: PCI\VEN_8086&DEV_7EC4&SUBSYS_50001458&REV_10\3&11583659&0&38 + Driver: C:\Windows\system32\DRIVERS\pci.sys, 10.00.19041.6456 (English), 10/30/2025 10:14:43, 473488 bytes + + Name: PCI Express Root Port +Device ID: PCI\VEN_8086&DEV_7ECC&SUBSYS_D0001458&REV_10\3&11583659&0&08 + Driver: C:\Windows\system32\DRIVERS\pci.sys, 10.00.19041.6456 (English), 10/30/2025 10:14:43, 473488 bytes + + Name: PCI Device +Device ID: PCI\VEN_8086&DEV_7F7A&SUBSYS_D0001458&REV_10\3&36CB97A3&0&C8 + Driver: n/a + + Name: PCI Device +Device ID: PCI\VEN_8086&DEV_AE23&SUBSYS_D0001458&REV_10\3&11583659&0&FD + Driver: n/a + + Name: PCI Express Root Port +Device ID: PCI\VEN_8086&DEV_AE4D&SUBSYS_50001458&REV_10\3&11583659&0&30 + Driver: C:\Windows\system32\DRIVERS\pci.sys, 10.00.19041.6456 (English), 10/30/2025 10:14:43, 473488 bytes + + Name: PCI Express Root Port +Device ID: PCI\VEN_8086&DEV_7F3C&SUBSYS_50011458&REV_10\3&36CB97A3&0&E4 + Driver: C:\Windows\system32\DRIVERS\pci.sys, 10.00.19041.6456 (English), 10/30/2025 10:14:43, 473488 bytes + + Name: PCI Device +Device ID: PCI\VEN_8086&DEV_7F4F&SUBSYS_D0001458&REV_10\3&36CB97A3&0&AB + Driver: n/a + + Name: Base System Device +Device ID: PCI\VEN_8086&DEV_AE4C&SUBSYS_D0001458&REV_10\3&11583659&0&40 + Driver: n/a + + Name: PCI standard ISA bridge +Device ID: PCI\VEN_8086&DEV_AE0D&SUBSYS_D0001458&REV_10\3&11583659&0&F8 + Driver: C:\Windows\system32\DRIVERS\msisadrv.sys, 10.00.19041.3636 (English), 7/18/2025 19:36:23, 21480 bytes + + Name: PCI Data Acquisition and Signal Processing Controller +Device ID: PCI\VEN_8086&DEV_AD03&SUBSYS_D0001458&REV_01\3&11583659&0&20 + Driver: n/a + + Name: Intel(R) Ethernet Controller I226-V #2 +Device ID: PCI\VEN_8086&DEV_125C&SUBSYS_E0001458&REV_04\10FFE0FFFF3A7D1500 + Driver: C:\Windows\System32\DriverStore\FileRepository\e2f.inf_amd64_d0d0d2073f0fc12f\e2f.sys, 1.01.0004.0043 (Indonesian), 5/13/2024 08:32:32, 536160 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\e2f.inf_amd64_d0d0d2073f0fc12f\e2fmsg.dll, 0.00.0000.0007 (English), 5/13/2024 08:32:32, 253640 bytes + + Name: Intel(R) Ethernet Controller I226-V +Device ID: PCI\VEN_8086&DEV_125C&SUBSYS_E0001458&REV_04\10FFE0FFFF3A7D1400 + Driver: C:\Windows\System32\DriverStore\FileRepository\e2f.inf_amd64_d0d0d2073f0fc12f\e2f.sys, 1.01.0004.0043 (Indonesian), 5/13/2024 08:32:32, 536160 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\e2f.inf_amd64_d0d0d2073f0fc12f\e2fmsg.dll, 0.00.0000.0007 (English), 5/13/2024 08:32:32, 253640 bytes + + Name: PCI Device +Device ID: PCI\VEN_8086&DEV_7F24&SUBSYS_D0001458&REV_10\3&36CB97A3&0&FD + Driver: n/a + + Name: Standard SATA AHCI Controller +Device ID: PCI\VEN_8086&DEV_7F62&SUBSYS_B0051458&REV_10\3&36CB97A3&0&B8 + Driver: C:\Windows\system32\DRIVERS\storahci.sys, 10.00.19041.3636 (English), 7/18/2025 19:36:23, 187376 bytes + + Name: Standard NVM Express Controller +Device ID: PCI\VEN_1CC1&DEV_5370&SUBSYS_53701CC1&REV_01\4&1515CA30&0&00EC + Driver: C:\Windows\system32\DRIVERS\stornvme.sys, 10.00.19041.4355 (English), 7/18/2025 19:36:23, 165232 bytes + + Name: PCI Device +Device ID: PCI\VEN_8086&DEV_7F4D&SUBSYS_D0001458&REV_10\3&36CB97A3&0&A9 + Driver: n/a + + Name: NVIDIA GeForce RTX 5060 Ti +Device ID: PCI\VEN_10DE&DEV_2D04&SUBSYS_53531462&REV_A1\11322F08412DB04800 + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\NVWMI\nvPerfProvider.man, 6/25/2025 09:36:53, 14175 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\NVWMI\nvWmi.mof, 6/25/2025 09:36:53, 148921 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\NVWMI\nvWmi64.exe, 2.36.0000.0000 (English), 6/25/2025 19:17:52, 4550784 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\Display.NvContainer\NVDisplay.Container.exe, 1.39.3323.1171 (English), 6/25/2025 19:17:30, 1275552 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\Display.NvContainer\NvContainerRecovery.bat, 6/25/2025 09:36:53, 1951 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\Display.NvContainer\NvMessageBus.dll, 3.15.3538.9611 (English), 6/25/2025 19:17:30, 3535480 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\Display.NvContainer\dlsargs.xml, 6/25/2025 09:36:53, 544 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\Display.NvContainer\dlsnetparams.csv, 6/25/2025 09:36:53, 459786 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\Display.NvContainer\messagebus_client.conf, 6/25/2025 09:36:53, 313 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\Display.NvContainer\nvgwls.exe, 6/25/2025 19:17:30, 3726440 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\Display.NvContainer\nvtopps.db3, 6/25/2025 09:36:53, 126976 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\Display.NvContainer\plugins\LocalSystem\NvXDCore.dll, 32.00.0015.7688 (English), 6/25/2025 19:17:34, 1951344 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\Display.NvContainer\plugins\LocalSystem\NvcDispCorePlugin.dll, 32.00.0015.7688 (English), 6/25/2025 19:17:32, 521352 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\Display.NvContainer\plugins\LocalSystem\NvcDispWatchdog.dll, 1.39.3323.1171 (English), 6/25/2025 19:17:32, 760456 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\Display.NvContainer\plugins\LocalSystem\_DisplayDriverRAS.dll, 1.10.0000.0000 (English), 6/25/2025 19:17:34, 2546840 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\Display.NvContainer\plugins\LocalSystem\_NvMsgBusBroadcast.dll, 3.15.3538.9611 (English), 6/25/2025 19:17:36, 3521168 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\Display.NvContainer\plugins\LocalSystem\_nvtopps.dll, 32.00.0015.7688 (English), 6/25/2025 19:17:36, 13168776 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\Display.NvContainer\plugins\LocalSystem\messagebus.conf, 6/25/2025 09:36:53, 313 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\Display.NvContainer\plugins\LocalSystem\wksServicePluginZ.dll, 32.00.0015.7688 (English), 6/25/2025 19:17:34, 280704 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\Display.NvContainer\plugins\Session\_NvGSTPlugin.dll, 32.00.0015.7688 (English), 6/25/2025 19:17:40, 2653824 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\Display.NvContainer\plugins\Session\nvprofileupdaterplugin.dll, 32.00.0015.7688 (English), 6/25/2025 19:17:38, 1976968 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\Display.NvContainer\plugins\Session\nvxdsyncplugin.dll, 8.17.0015.7688 (English), 6/25/2025 19:17:38, 1844848 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\Display.NvContainer\plugins\Session\wksServicePlugin.dll, 32.00.0015.7688 (English), 6/25/2025 19:17:40, 314504 bytes + Driver: C:\Windows\system32\DRIVERS\NVIDIA Corporation\Drs\dbInstaller.exe, 32.00.0015.7688 (English), 6/25/2025 19:10:56, 822936 bytes + Driver: C:\Windows\system32\DRIVERS\NVIDIA Corporation\Drs\nvdrsdb.bin, 6/25/2025 09:36:53, 2056752 bytes + Driver: C:\Windows\system32\nvcpl.dll, 8.17.0015.7688 (English), 6/25/2025 19:11:14, 5917832 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\nv3dappshext.dll, 6.14.0015.7688 (English), 6/25/2025 19:11:08, 1005696 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\nv3dappshextr.dll, 6.14.0015.7688 (English), 6/25/2025 19:11:08, 98464 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\nvcoproc.bin, 6/25/2025 09:36:53, 12152603 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\nvcpl.dll, 8.17.0015.7688 (English), 6/25/2025 19:11:14, 5917832 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\nvdevtools.dll, 32.00.0015.7688 (English), 6/25/2025 19:12:02, 4603016 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\nvdevtoolsr.dll, 32.00.0015.7688 (English), 6/25/2025 19:12:06, 245384 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\nvdisps.dll, 32.00.0015.7688 (English), 6/25/2025 19:12:06, 11667072 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\nvdispsr.dll, 32.00.0015.7688 (English), 6/25/2025 19:12:08, 11573896 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\nvgames.dll, 32.00.0015.7688 (English), 6/25/2025 19:12:28, 12513432 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\nvgamesr.dll, 32.00.0015.7688 (English), 6/25/2025 19:12:30, 13321352 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\nvlicensings.dll, 6.14.0015.7688 (English), 6/25/2025 19:13:20, 4585112 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\nvlicensingsr.dll, 6.14.0015.7688 (English), 6/25/2025 19:13:22, 363144 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\nvshext.dll, 1.02.0000.0001 (English), 6/25/2025 19:15:58, 133784 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\nvsmartmax.dll, 6.14.0010.10003 (English), 6/25/2025 19:16:00, 200344 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\nvsmartmax64.dll, 6.14.0010.10003 (English), 6/25/2025 19:16:00, 236656 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\nvsmartmaxapp.exe, 6.14.0010.10003 (English), 6/25/2025 19:16:02, 274592 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\nvsmartmaxapp64.exe, 6.14.0010.10003 (English), 6/25/2025 19:16:02, 284808 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\nvsvc64.dll, 32.00.0015.7688 (Indonesian), 6/25/2025 19:16:04, 2677896 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\nvsvcr.dll, 32.00.0015.7688 (Indonesian), 6/25/2025 19:16:06, 1801328 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\nvsvs.dll, 32.00.0015.7688 (English), 6/25/2025 19:16:06, 5110408 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\nvsvsr.dll, 32.00.0015.7688 (English), 6/25/2025 19:16:08, 2012320 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\nvui.dll, 8.17.0015.7688 (English), 6/25/2025 19:16:10, 6668904 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\nvuir.dll, 8.17.0015.7688 (English), 6/25/2025 19:16:12, 2650248 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\nvvitvs.dll, 32.00.0015.7688 (English), 6/25/2025 19:16:16, 7473800 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\nvvitvsr.dll, 32.00.0015.7688 (English), 6/25/2025 19:16:18, 4263528 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\nvwss.dll, 32.00.0015.7688 (English), 6/25/2025 19:17:04, 12279424 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\nvwssr.dll, 32.00.0015.7688 (English), 6/25/2025 19:17:06, 9529456 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\nvxdapix.dll, 8.17.0015.7688 (English), 6/25/2025 19:17:08, 9581680 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\nvxdbat.dll, 8.17.0015.7688 (English), 6/25/2025 19:17:12, 1657472 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\nvxdplcy.dll, 8.17.0015.7688 (English), 6/25/2025 19:17:14, 1899144 bytes + Driver: C:\Windows\system32\lxss\lib\libcuda.so, 6/25/2025 09:36:53, 171008 bytes + Driver: C:\Windows\system32\lxss\lib\libcuda.so.1, 6/25/2025 09:36:53, 171008 bytes + Driver: C:\Windows\system32\lxss\lib\libcuda.so.1.1, 6/25/2025 09:36:53, 171008 bytes + Driver: C:\Windows\system32\lxss\lib\libcudadebugger.so.1, 6/25/2025 09:36:53, 9742088 bytes + Driver: C:\Windows\system32\lxss\lib\libnvcuvid.so, 6/25/2025 09:36:53, 19020552 bytes + Driver: C:\Windows\system32\lxss\lib\libnvcuvid.so.1, 6/25/2025 09:36:53, 19020552 bytes + Driver: C:\Windows\system32\lxss\lib\libnvdxdlkernels.so, 6/25/2025 09:36:53, 153723328 bytes + Driver: C:\Windows\system32\lxss\lib\libnvidia-encode.so, 6/25/2025 09:36:53, 272448 bytes + Driver: C:\Windows\system32\lxss\lib\libnvidia-encode.so.1, 6/25/2025 09:36:53, 272448 bytes + Driver: C:\Windows\system32\lxss\lib\libnvidia-ml.so.1, 6/25/2025 09:36:53, 260880 bytes + Driver: C:\Windows\system32\lxss\lib\libnvidia-ngx.so.1, 6/25/2025 09:36:53, 4578440 bytes + Driver: C:\Windows\system32\lxss\lib\libnvidia-opticalflow.so, 6/25/2025 09:36:53, 67584 bytes + Driver: C:\Windows\system32\lxss\lib\libnvidia-opticalflow.so.1, 6/25/2025 09:36:53, 67584 bytes + Driver: C:\Windows\system32\lxss\lib\libnvoptix.so.1, 6/25/2025 09:36:53, 72616 bytes + Driver: C:\Windows\system32\lxss\lib\libnvwgf2umx.so, 6/25/2025 09:36:53, 99210584 bytes + Driver: C:\Windows\system32\lxss\lib\nvidia-ngx-updater, 6/25/2025 09:36:53, 5047376 bytes + Driver: C:\Windows\system32\lxss\lib\nvidia-smi, 6/25/2025 09:36:53, 823096 bytes + Driver: C:\Windows\system32\DRIVERS\NVIDIA Corporation\license.txt, 6/25/2025 09:36:53, 44190 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\_nvngx.dll, 32.00.0015.7688 (English), 6/25/2025 19:17:28, 1410672 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\nvngx.dll, 30.00.0014.9516 (English), 6/25/2025 19:13:26, 488808 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\nvngx_dlss.dll, 3.08.0010.0000 (English), 6/25/2025 19:13:28, 24925856 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\nvngx_dlssg.dll, 310.02.0001.0000 (English), 6/25/2025 19:13:34, 9299584 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\nvngx_update.exe, 32.00.0015.7688 (English), 6/25/2025 19:13:36, 967808 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\NvCamera\FreqTransfer32.exe, 6/25/2025 19:17:42, 3764336 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\NvCamera\FreqTransfer64.exe, 6/25/2025 19:17:44, 4057224 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\NvCamera\GreenScreenBG01.jpg, 6/25/2025 09:36:53, 281528 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\NvCamera\GreenScreenBG02.jpg, 6/25/2025 09:36:53, 499736 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\NvCamera\HighresBlender32.exe, 6/25/2025 19:17:44, 3861120 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\NvCamera\HighresBlender64.exe, 6/25/2025 19:17:44, 4163176 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\NvCamera\NvCamera32.dll, 7.01.0000.0000 (English), 6/25/2025 19:17:46, 8199008 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\NvCamera\NvCamera64.dll, 7.01.0000.0000 (English), 6/25/2025 19:17:46, 8710424 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\NvCamera\NvCameraAllowlisting32.dll, 7.01.0000.0000 (English), 6/25/2025 19:17:46, 531680 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\NvCamera\NvCameraAllowlisting64.dll, 7.01.0000.0000 (English), 6/25/2025 19:17:48, 677928 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\NvCamera\NvCameraEnable.exe, 6/25/2025 19:17:48, 375424 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\NvCamera\NvImageConvert32.exe, 6/25/2025 19:17:48, 3763816 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\NvCamera\NvImageConvert64.exe, 6/25/2025 19:17:48, 4038272 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\NvCamera\ReShadeFXC32.exe, 2.00.0000.0000 (English), 6/25/2025 19:17:50, 776808 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\NvCamera\ReShadeFXC64.exe, 2.00.0000.0000 (English), 6/25/2025 19:17:50, 891504 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\NvCamera\ShotWithGeforce518x32.rgba, 6/25/2025 09:36:53, 66304 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\NvCamera\SphericalEquirect32.exe, 6/25/2025 19:17:50, 3717248 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\NvCamera\SphericalEquirect64.exe, 6/25/2025 19:17:52, 3941504 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\NvCamera\Sticker01.png, 6/25/2025 09:36:53, 49695 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\NvCamera\Sticker02.png, 6/25/2025 09:36:53, 474002 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\NvCamera\Sticker03.png, 6/25/2025 09:36:53, 380006 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\NvCamera\Sticker04.png, 6/25/2025 09:36:53, 86881 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\NvCamera\Sticker05.png, 6/25/2025 09:36:53, 59304 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\NvCamera\Sticker06.png, 6/25/2025 09:36:53, 13547 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\NvCamera\Sticker07.png, 6/25/2025 09:36:53, 6342 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\NvCamera\Sticker08.png, 6/25/2025 09:36:53, 96493 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\NvCamera\d3dcompiler_47_32.dll, 6.03.9600.16384 (English), 6/25/2025 19:17:40, 3470984 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\NvCamera\d3dcompiler_47_64.dll, 6.03.9600.16384 (English), 6/25/2025 19:17:42, 4178032 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\NvCamera\scratches.jpg, 6/25/2025 09:36:53, 346354 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\NvCamera\tools_licenses.txt, 6/25/2025 09:36:53, 15970 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\NvCamera\ui.tga, 6/25/2025 09:36:53, 121321 bytes + Driver: C:\Windows\system32\MCU.exe, 1.01.5204.20580 (Indonesian), 6/25/2025 19:11:06, 853632 bytes + Driver: C:\Windows\system32\nvdebugdump.exe, 6.14.0015.7688 (English), 6/25/2025 19:12:00, 467608 bytes + Driver: C:\Windows\system32\nvidia-smi.exe, 8.17.0015.7688 (English), 6/25/2025 19:12:46, 942208 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\nvopencl32.dll, 32.00.0015.7688 (English), 6/25/2025 19:14:02, 38040176 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\nvopencl64.dll, 32.00.0015.7688 (English), 6/25/2025 19:14:12, 35019912 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\nvlddmkm.sys, 32.00.0015.7688 (English), 6/25/2025 19:13:00, 111668848 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\nvvm32.dll, 32.00.0015.7688 (English), 6/25/2025 19:16:24, 60573808 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\nvvm64.dll, 32.00.0015.7688 (English), 6/25/2025 19:16:40, 68843168 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\nvvm70.dll, 6.14.0011.9000 (English), 6/25/2025 19:16:58, 18979968 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\NvMemMapStorage.dll, 6/25/2025 19:12:06, 713432 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\NvMemMapStorageax.dll, 6/25/2025 19:12:08, 1033480 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\NvMemMapStorageaxec.dll, 6/25/2025 19:12:08, 1236672 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\NvMemMapStoragex.dll, 6/25/2025 19:12:10, 915088 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\NvPresent64.dll, 6/25/2025 19:14:52, 60506736 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\OscTool.exe, 6/25/2025 19:17:18, 2371232 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\gsp_ga10x.bin, 6/25/2025 09:36:53, 74544880 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\gsp_tu10x.bin, 6/25/2025 09:36:53, 29508696 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\libcuda.so.1.1, 6/25/2025 09:36:53, 25912104 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\libcuda_loader.so, 6/25/2025 09:36:53, 171008 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\libcudadebugger.so.1, 6/25/2025 09:36:53, 9742088 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\libnvcuvid.so.1, 6/25/2025 09:36:53, 19020552 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\libnvdxdlkernels.so, 6/25/2025 09:36:53, 153723328 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\libnvdxgdmal.so.1, 6/25/2025 09:36:53, 59392 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\libnvidia-encode.so.1, 6/25/2025 09:36:53, 272448 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\libnvidia-ml.so.1, 6/25/2025 09:36:53, 1939624 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\libnvidia-ml_loader.so, 6/25/2025 09:36:53, 260880 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\libnvidia-nvvm.so.4, 6/25/2025 09:36:53, 22924888 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\libnvidia-opticalflow.so.1, 6/25/2025 09:36:53, 67584 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\libnvidia-ptxjitcompiler.so.1, 6/25/2025 09:36:53, 40431128 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\libnvoptix_loader.so.1, 6/25/2025 09:36:53, 72616 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\libnvwgf2umx.so, 6/25/2025 09:36:53, 99210584 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\nv-vk64.json, 6/25/2025 09:36:53, 1182 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\nv-vksc64.json, 6/25/2025 09:36:53, 1179 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\nvAIDVC.dll, 32.00.0015.7688 (English), 6/25/2025 19:11:10, 2727024 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\nvAIDVCx.dll, 32.00.0015.7688 (English), 6/25/2025 19:11:10, 2837608 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\nvAIHDR.dll, 32.00.0015.7688 (English), 6/25/2025 19:10:46, 3720552 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\nvAIHDRx.dll, 32.00.0015.7688 (English), 6/25/2025 19:10:48, 3851808 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\nvDecMFTMjpeg.dll, 32.00.0015.7688 (English), 6/25/2025 19:12:00, 510576 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\nvDecMFTMjpegx.dll, 32.00.0015.7688 (English), 6/25/2025 19:12:02, 666784 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\nvEncMFTH264.dll, 32.00.0015.7688 (English), 6/25/2025 19:12:18, 896624 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\nvEncMFTH264x.dll, 32.00.0015.7688 (English), 6/25/2025 19:12:20, 1143960 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\nvEncMFTav1.dll, 32.00.0015.7688 (English), 6/25/2025 19:12:16, 889472 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\nvEncMFTav1x.dll, 32.00.0015.7688 (English), 6/25/2025 19:12:18, 1134744 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\nvEncMFThevc.dll, 32.00.0015.7688 (English), 6/25/2025 19:12:22, 907880 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\nvEncMFThevcx.dll, 32.00.0015.7688 (English), 6/25/2025 19:12:22, 1160832 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\nvcubins.bin, 6/25/2025 09:36:53, 75846620 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\nvcuda32.dll, 32.00.0015.7688 (English), 6/25/2025 19:11:16, 42367080 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\nvcuda64.dll, 32.00.0015.7688 (English), 6/25/2025 19:11:28, 34139272 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\nvd3dumx.dll, 32.00.0015.7688 (English), 6/25/2025 19:11:12, 36503048 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\nvdlistx.dll, 32.00.0015.7688 (English), 6/25/2025 19:11:24, 240808 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\nvdlppx.dll, 32.00.0015.7688 (English), 6/25/2025 19:11:26, 22161144 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\nvdxdlkernels.dll, 32.00.0015.7688 (English), 6/25/2025 19:12:14, 217308808 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\nvdxgdmal32.dll, 6/25/2025 19:12:14, 474752 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\nvdxgdmal64.dll, 6/25/2025 19:12:16, 604264 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\nvgpucomp32.dll, 32.00.0015.7688 (English), 6/25/2025 19:11:32, 50533560 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\nvgpucomp64.dll, 32.00.0015.7688 (English), 6/25/2025 19:11:48, 61853024 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\nvidia-smi, 6/25/2025 09:36:53, 823096 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\nvldumdx.dll, 32.00.0015.7688 (English), 6/25/2025 19:12:04, 810616 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\nvml.dll, 8.17.0015.7688 (English), 6/25/2025 19:13:24, 1778336 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\nvoglv64.dll, 32.00.0015.7688 (English), 6/25/2025 19:13:50, 41950344 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\nvoptix.bin, 6/25/2025 09:36:53, 60858204 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\nvoptix.dll, 9.00.0001.0000 (English), 6/25/2025 19:14:24, 103853704 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\nvppe.dll, 32.00.0015.7688 (English), 6/25/2025 19:12:10, 1318176 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\nvppex.dll, 32.00.0015.7688 (English), 6/25/2025 19:12:12, 1807600 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\nvptxJitCompiler32.dll, 32.00.0015.7688 (English), 6/25/2025 19:15:08, 23605352 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\nvptxJitCompiler64.dll, 32.00.0015.7688 (English), 6/25/2025 19:15:16, 27236488 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\nvrtum64.dll, 32.00.0015.7688 (English), 6/25/2025 19:15:26, 118592672 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\nvvkscv64.dll, 32.00.0015.7688 (English), 6/25/2025 19:16:20, 11561072 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\nvwgf2umx.dll, 32.00.0015.7688 (English), 6/25/2025 19:12:42, 89547696 bytes + Driver: C:\Windows\system32\NvFBC64.dll, 6.14.0015.7688 (English), 6/25/2025 19:12:26, 2313856 bytes + Driver: C:\Windows\system32\NvIFR64.dll, 6.14.0015.7688 (English), 6/25/2025 19:12:56, 1568904 bytes + Driver: C:\Windows\system32\OpenCL.dll, 3.00.0006.0000 (English), 6/25/2025 19:17:18, 477800 bytes + Driver: C:\Windows\system32\nvEncodeAPI64.dll, 32.00.0015.7688 (English), 6/25/2025 19:12:24, 1053296 bytes + Driver: C:\Windows\system32\nvapi64.dll, 32.00.0015.7688 (English), 6/25/2025 19:10:52, 5602096 bytes + Driver: C:\Windows\system32\nvcuda.dll, 32.00.0015.7688 (English), 6/25/2025 19:11:42, 3993704 bytes + Driver: C:\Windows\system32\nvcudadebugger.dll, 0.00.0000.0000 (English), 6/25/2025 19:11:36, 5239920 bytes + Driver: C:\Windows\system32\nvcuvid.dll, 7.17.0015.7688 (English), 6/25/2025 19:11:52, 23035016 bytes + Driver: C:\Windows\system32\nvidia-pcc.exe, 6/25/2025 19:12:38, 26004632 bytes + Driver: C:\Windows\system32\nvinfo.pb, 6/25/2025 09:36:53, 143026 bytes + Driver: C:\Windows\system32\nvml.dll, 8.17.0015.7688 (English), 6/25/2025 19:13:24, 1259656 bytes + Driver: C:\Windows\system32\nvofapi64.dll, 32.00.0015.7688 (English), 6/25/2025 19:13:40, 674440 bytes + Driver: C:\Windows\system32\vulkan-1-999-0-0-0.dll, 1.04.0303.0000 (English), 6/25/2025 19:17:22, 1576800 bytes + Driver: C:\Windows\system32\vulkan-1.dll, 1.04.0303.0000 (English), 6/25/2025 19:17:22, 1576800 bytes + Driver: C:\Windows\system32\vulkaninfo-1-999-0-0-0.exe, 1.04.0303.0000 (English), 6/25/2025 19:17:26, 2072424 bytes + Driver: C:\Windows\system32\vulkaninfo.exe, 1.04.0303.0000 (English), 6/25/2025 19:17:26, 2072424 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\nv-vk32.json, 6/25/2025 09:36:53, 1182 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\nvIccAdvancedColorIdentity.icm, 6/25/2025 09:36:53, 3288 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\nvd3dum.dll, 32.00.0015.7688 (English), 6/25/2025 19:10:56, 60937736 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\nvdispco64.exe, 1.00.0016.0000 (English), 6/25/2025 19:12:06, 1740400 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\nvdlist.dll, 32.00.0015.7688 (English), 6/25/2025 19:11:22, 203816 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\nvldumd.dll, 32.00.0015.7688 (English), 6/25/2025 19:12:04, 646456 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\nvoglv32.dll, 32.00.0015.7688 (English), 6/25/2025 19:13:42, 25672352 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\nvwgf2um.dll, 32.00.0015.7688 (English), 6/25/2025 19:12:16, 86660272 bytes + Driver: C:\Windows\SysWow64\NvFBC.dll, 6.14.0015.7688 (English), 6/25/2025 19:12:26, 1713288 bytes + Driver: C:\Windows\SysWow64\NvIFR.dll, 6.14.0015.7688 (English), 6/25/2025 19:12:54, 1220232 bytes + Driver: C:\Windows\SysWow64\OpenCL.dll, 3.00.0006.0000 (English), 6/25/2025 19:17:16, 374912 bytes + Driver: C:\Windows\SysWow64\nvEncodeAPI.dll, 32.00.0015.7688 (English), 6/25/2025 19:12:24, 809584 bytes + Driver: C:\Windows\SysWow64\nvapi.dll, 32.00.0015.7688 (English), 6/25/2025 19:10:48, 4902176 bytes + Driver: C:\Windows\SysWow64\nvcuda.dll, 32.00.0015.7688 (English), 6/25/2025 19:11:38, 7322728 bytes + Driver: C:\Windows\SysWow64\nvcuvid.dll, 7.17.0015.7688 (English), 6/25/2025 19:11:44, 20516976 bytes + Driver: C:\Windows\SysWow64\nvofapi.dll, 32.00.0015.7688 (English), 6/25/2025 19:13:38, 508552 bytes + Driver: C:\Windows\SysWow64\vulkan-1-999-0-0-0.dll, 1.04.0303.0000 (English), 6/25/2025 19:17:24, 1389952 bytes + Driver: C:\Windows\SysWow64\vulkan-1.dll, 1.04.0303.0000 (English), 6/25/2025 19:17:24, 1389952 bytes + Driver: C:\Windows\SysWow64\vulkaninfo-1-999-0-0-0.exe, 1.04.0303.0000 (English), 6/25/2025 19:17:26, 1614184 bytes + Driver: C:\Windows\SysWow64\vulkaninfo.exe, 1.04.0303.0000 (English), 6/25/2025 19:17:26, 1614184 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\nvmdi.inf_amd64_fb80e95fa979ce23\NvTelemetry64.dll, 14.03.0060.0000 (English), 6/25/2025 19:16:10, 4466256 bytes + + Name: PCI Express Root Port +Device ID: PCI\VEN_8086&DEV_7F39&SUBSYS_50011458&REV_10\3&36CB97A3&0&E1 + Driver: C:\Windows\system32\DRIVERS\pci.sys, 10.00.19041.6456 (English), 10/30/2025 10:14:43, 473488 bytes + + Name: PCI Express Root Port +Device ID: PCI\VEN_8086&DEV_7EC5&SUBSYS_50001458&REV_10\3&11583659&0&39 + Driver: C:\Windows\system32\DRIVERS\pci.sys, 10.00.19041.6456 (English), 10/30/2025 10:14:43, 473488 bytes + + Name: PCI Express Root Port +Device ID: PCI\VEN_8086&DEV_7F30&SUBSYS_D0001458&REV_10\3&36CB97A3&0&E8 + Driver: C:\Windows\system32\DRIVERS\pci.sys, 10.00.19041.6456 (English), 10/30/2025 10:14:43, 473488 bytes + + Name: PCI Device +Device ID: PCI\VEN_8086&DEV_7F7B&SUBSYS_D0001458&REV_10\3&36CB97A3&0&C9 + Driver: n/a + + Name: Intel(R) USB 3.20 eXtensible Host Controller - 1.20 (Microsoft) +Device ID: PCI\VEN_8086&DEV_7EC0&SUBSYS_50071458&REV_10\3&11583659&0&68 + Driver: C:\Windows\system32\DRIVERS\USBXHCI.SYS, 10.00.19041.5794 (English), 7/18/2025 19:36:24, 620472 bytes + Driver: C:\Windows\system32\DRIVERS\UMDF\UsbXhciCompanion.dll, 10.00.19041.5794 (English), 7/18/2025 19:36:24, 143768 bytes + + Name: PCI Device +Device ID: PCI\VEN_8086&DEV_7F2B&SUBSYS_D0001458&REV_10\3&36CB97A3&0&F3 + Driver: n/a + + Name: Intel(R) Wi-Fi 7 BE202 160MHz +Device ID: PCI\VEN_8086&DEV_272B&SUBSYS_02F48086&REV_1A\4&10DA6E4&0&00E3 + Driver: C:\Windows\System32\DriverStore\FileRepository\netwtw6e.inf_amd64_1dcc048ae0ea02f8\Netwtw18.sys, 24.40.0000.0004 (English), 4/15/2026 03:57:48, 6167464 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\netwtw6e.inf_amd64_1dcc048ae0ea02f8\netwfw18.dat, 4/15/2026 03:57:48, 22887132 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\netwtw6e.inf_amd64_1dcc048ae0ea02f8\IntelIHVRouter18.dll, 24.12040.0000.0001 (English), 4/15/2026 03:57:48, 1624488 bytes + + Name: Intel(R) Management Engine Interface #1 +Device ID: PCI\VEN_8086&DEV_7F68&SUBSYS_1C3A1458&REV_10\3&36CB97A3&0&B0 + Driver: C:\Windows\System32\DriverStore\FileRepository\heci.inf_amd64_6b6e8cc42a3d1f09\x64\TeeDriverW10x64.sys, 2406.05.0005.0000 (English), 2/14/2024 17:22:52, 323264 bytes + + Name: High Definition Audio Controller +Device ID: PCI\VEN_8086&DEV_7F50&SUBSYS_A0C31458&REV_10\3&36CB97A3&0&FB + Driver: C:\Windows\system32\DRIVERS\hdaudbus.sys, 10.00.19041.6157 (English), 8/28/2025 08:20:02, 135168 bytes + Driver: C:\Windows\system32\DRIVERS\drmk.sys, 10.00.19041.5072 (English), 7/18/2025 19:36:23, 97792 bytes + Driver: C:\Windows\system32\DRIVERS\portcls.sys, 10.00.19041.5072 (English), 7/18/2025 19:36:23, 388608 bytes + + Name: Intel(R) Platform Monitoring Technology (PMT) Driver +Device ID: PCI\VEN_8086&DEV_AD0D&SUBSYS_D0001458&REV_01\3&11583659&0&50 + Driver: C:\Windows\System32\DriverStore\FileRepository\intcpmt.inf_amd64_a64daebcd9a15598\intcpmt.sys, 10.00.10011.16384 (English), 6/13/2023 05:40:38, 66496 bytes + + Name: SM Bus Controller +Device ID: PCI\VEN_8086&DEV_7F23&SUBSYS_50011458&REV_10\3&36CB97A3&0&FC + Driver: n/a + + Name: High Definition Audio Controller +Device ID: PCI\VEN_10DE&DEV_22EB&SUBSYS_000010DE&REV_A1\4&272C504F&0&0130 + Driver: C:\Windows\system32\DRIVERS\hdaudbus.sys, 10.00.19041.6157 (English), 8/28/2025 08:20:02, 135168 bytes + Driver: C:\Windows\system32\DRIVERS\drmk.sys, 10.00.19041.5072 (English), 7/18/2025 19:36:23, 97792 bytes + Driver: C:\Windows\system32\DRIVERS\portcls.sys, 10.00.19041.5072 (English), 7/18/2025 19:36:23, 388608 bytes + + Name: Standard NVM Express Controller +Device ID: PCI\VEN_144D&DEV_A810&SUBSYS_A801144D&REV_00\4&50C4F90&0&0008 + Driver: C:\Windows\system32\DRIVERS\stornvme.sys, 10.00.19041.4355 (English), 7/18/2025 19:36:23, 165232 bytes + + Name: PCI Express Root Port +Device ID: PCI\VEN_8086&DEV_7F3B&SUBSYS_50011458&REV_10\3&36CB97A3&0&E3 + Driver: C:\Windows\system32\DRIVERS\pci.sys, 10.00.19041.6456 (English), 10/30/2025 10:14:43, 473488 bytes + + Name: Universal Serial Bus (USB) Controller +Device ID: PCI\VEN_8086&DEV_7EC2&SUBSYS_D0001458&REV_10\3&11583659&0&6A + Driver: n/a + + Name: Standard NVM Express Controller +Device ID: PCI\VEN_1CC1&DEV_648A&SUBSYS_648A1CC1&REV_01\4&167CEF57&0&00E4 + Driver: C:\Windows\system32\DRIVERS\stornvme.sys, 10.00.19041.4355 (English), 7/18/2025 19:36:23, 165232 bytes + + Name: PCI Device +Device ID: PCI\VEN_8086&DEV_7F4E&SUBSYS_D0001458&REV_10\3&36CB97A3&0&AA + Driver: n/a + + Name: PCI Simple Communications Controller +Device ID: PCI\VEN_8086&DEV_7F28&SUBSYS_D0001458&REV_10\3&36CB97A3&0&F0 + Driver: n/a + + Name: PCI standard ISA bridge +Device ID: PCI\VEN_8086&DEV_7F04&SUBSYS_50011458&REV_10\3&36CB97A3&0&F8 + Driver: C:\Windows\system32\DRIVERS\msisadrv.sys, 10.00.19041.3636 (English), 7/18/2025 19:36:23, 21480 bytes + + Name: PCI Express Root Port +Device ID: PCI\VEN_8086&DEV_7F34&SUBSYS_D0001458&REV_10\3&36CB97A3&0&EC + Driver: C:\Windows\system32\DRIVERS\pci.sys, 10.00.19041.6456 (English), 10/30/2025 10:14:43, 473488 bytes + + Name: Intel(R) USB 3.20 eXtensible Host Controller - 1.20 (Microsoft) +Device ID: PCI\VEN_8086&DEV_7F6E&SUBSYS_D0001458&REV_10\3&36CB97A3&0&A0 + Driver: C:\Windows\system32\DRIVERS\USBXHCI.SYS, 10.00.19041.5794 (English), 7/18/2025 19:36:24, 620472 bytes + Driver: C:\Windows\system32\DRIVERS\UMDF\UsbXhciCompanion.dll, 10.00.19041.5794 (English), 7/18/2025 19:36:24, 143768 bytes + + Name: Intel(R) Reserved Device +Device ID: PCI\VEN_8086&DEV_AD1D&SUBSYS_72701458&REV_01\3&11583659&0&58 + Driver: C:\Windows\System32\DriverStore\FileRepository\npu.inf_amd64_bf9f5ae081460842\npu_d3d12_umd.dll, 32.00.0100.3053 (English), 11/1/2024 09:59:36, 2361056 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\npu.inf_amd64_bf9f5ae081460842\npu_kmd.sys, 32.00.0100.3053 (English), 11/1/2024 09:59:42, 607080 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\npu.inf_amd64_bf9f5ae081460842\firmware\npu2_7_firmware.bin, 11/1/2024 09:49:22, 2358924 bytes + Driver: C:\Windows\System32\DriverStore\FileRepository\npu.inf_amd64_bf9f5ae081460842\third-party-programs.txt, 11/1/2024 09:49:22, 193266 bytes + +------------------ +DirectShow Filters +------------------ + +DirectShow Filters: +WMAudio Decoder DMO,0x00800800,1,1,WMADMOD.DLL,10.00.19041.6093 +WMAPro over S/PDIF DMO,0x00600800,1,1,WMADMOD.DLL,10.00.19041.6093 +WMSpeech Decoder DMO,0x00600800,1,1,WMSPDMOD.DLL,10.00.19041.0001 +MP3 Decoder DMO,0x00600800,1,1,mp3dmod.dll,10.00.19041.0001 +Mpeg4s Decoder DMO,0x00800001,1,1,mp4sdecd.dll,10.00.19041.6093 +WMV Screen decoder DMO,0x00600800,1,1,wmvsdecd.dll,10.00.19041.6093 +WMVideo Decoder DMO,0x00800001,1,1,wmvdecod.dll,10.00.19041.6456 +Mpeg43 Decoder DMO,0x00800001,1,1,mp43decd.dll,10.00.19041.3636 +MS ATC Screen Decoder 1,0x00600800,1,1,scdec.dll,15.00.4703.1000 +Mpeg4 Decoder DMO,0x00800001,1,1,mpg4decd.dll,10.00.19041.3636 +DV Muxer,0x00400000,0,0,qdv.dll,10.00.19041.0001 +Color Space Converter,0x00400001,1,1,quartz.dll,10.00.19041.5856 +WM ASF Reader,0x00400000,0,0,qasf.dll,12.00.19041.0001 +AVI Splitter,0x00600000,1,1,quartz.dll,10.00.19041.5856 +VGA 16 Color Ditherer,0x00400000,1,1,quartz.dll,10.00.19041.5856 +SBE2MediaTypeProfile,0x00200000,0,0,sbe.dll,10.00.19041.0001 +Microsoft DTV-DVD Video Decoder,0x005fffff,2,4,msmpeg2vdec.dll,10.00.19041.6456 +AC3 Parser Filter,0x00600000,1,1,mpg2splt.ax,10.00.19041.3636 +StreamBufferSink,0x00200000,0,0,sbe.dll,10.00.19041.0001 +MJPEG Decompressor,0x00600000,1,1,quartz.dll,10.00.19041.5856 +MPEG-I Stream Splitter,0x00600000,1,2,quartz.dll,10.00.19041.5856 +SAMI (CC) Parser,0x00400000,1,1,quartz.dll,10.00.19041.5856 +VBI Codec,0x00600000,1,4,VBICodec.ax,10.00.19041.3636 +MPEG-2 Splitter,0x005fffff,1,0,mpg2splt.ax,10.00.19041.3636 +Closed Captions Analysis Filter,0x00200000,2,5,cca.dll,10.00.19041.0001 +SBE2FileScan,0x00200000,0,0,sbe.dll,10.00.19041.0001 +Microsoft MPEG-2 Video Encoder,0x00200000,1,1,msmpeg2enc.dll,10.00.19041.6093 +Internal Script Command Renderer,0x00800001,1,0,quartz.dll,10.00.19041.5856 +MPEG Audio Decoder,0x03680001,1,1,quartz.dll,10.00.19041.5856 +DV Splitter,0x00600000,1,2,qdv.dll,10.00.19041.0001 +Video Mixing Renderer 9,0x00200000,1,0,quartz.dll,10.00.19041.5856 +Microsoft MPEG-2 Encoder,0x00200000,2,1,msmpeg2enc.dll,10.00.19041.6093 +ACM Wrapper,0x00600000,1,1,quartz.dll,10.00.19041.5856 +Video Renderer,0x00800001,1,0,quartz.dll,10.00.19041.5856 +MPEG-2 Video Stream Analyzer,0x00200000,0,0,sbe.dll,10.00.19041.0001 +Line 21 Decoder,0x00600000,1,1,, +Video Port Manager,0x00600000,2,1,quartz.dll,10.00.19041.5856 +Video Renderer,0x00400000,1,0,quartz.dll,10.00.19041.5856 +VPS Decoder,0x00200000,0,0,WSTPager.ax,10.00.19041.0001 +WM ASF Writer,0x00400000,0,0,qasf.dll,12.00.19041.0001 +VBI Surface Allocator,0x00600000,1,1,vbisurf.ax, +File writer,0x00200000,1,0,qcap.dll,10.00.19041.0001 +DVD Navigator,0x00200000,0,3,qdvd.dll,10.00.19041.3636 +Overlay Mixer2,0x00200000,1,1,, +AVI Draw,0x00600064,9,1,quartz.dll,10.00.19041.5856 +Microsoft MPEG-2 Audio Encoder,0x00200000,1,1,msmpeg2enc.dll,10.00.19041.6093 +WST Pager,0x00200000,1,1,WSTPager.ax,10.00.19041.0001 +MPEG-2 Demultiplexer,0x00600000,1,1,mpg2splt.ax,10.00.19041.3636 +DV Video Decoder,0x00800000,1,1,qdv.dll,10.00.19041.0001 +SampleGrabber,0x00200000,1,1,qedit.dll,10.00.19041.4355 +Null Renderer,0x00200000,1,0,qedit.dll,10.00.19041.4355 +MPEG-2 Sections and Tables,0x005fffff,1,0,Mpeg2Data.ax,10.00.19041.0001 +Microsoft AC3 Encoder,0x00200000,1,1,msac3enc.dll,10.00.19041.0001 +StreamBufferSource,0x00200000,0,0,sbe.dll,10.00.19041.0001 +Smart Tee,0x00200000,1,2,qcap.dll,10.00.19041.0001 +Overlay Mixer,0x00200000,0,0,, +AVI Decompressor,0x00600000,1,1,quartz.dll,10.00.19041.5856 +AVI/WAV File Source,0x00400000,0,2,quartz.dll,10.00.19041.5856 +Wave Parser,0x00400000,1,1,quartz.dll,10.00.19041.5856 +MIDI Parser,0x00400000,1,1,quartz.dll,10.00.19041.5856 +Multi-file Parser,0x00400000,1,1,quartz.dll,10.00.19041.5856 +File stream renderer,0x00400000,1,1,quartz.dll,10.00.19041.5856 +Microsoft DTV-DVD Audio Decoder,0x005fffff,1,1,msmpeg2adec.dll,10.00.19041.6456 +StreamBufferSink2,0x00200000,0,0,sbe.dll,10.00.19041.0001 +AVI Mux,0x00200000,1,0,qcap.dll,10.00.19041.0001 +Line 21 Decoder 2,0x00600002,1,1,quartz.dll,10.00.19041.5856 +File Source (Async.),0x00400000,0,1,quartz.dll,10.00.19041.5856 +File Source (URL),0x00400000,0,1,quartz.dll,10.00.19041.5856 +Infinite Pin Tee Filter,0x00200000,1,1,qcap.dll,10.00.19041.0001 +Enhanced Video Renderer,0x00200000,1,0,evr.dll,10.00.19041.5794 +BDA MPEG2 Transport Information Filter,0x00200000,2,0,psisrndr.ax,10.00.19041.0001 +MPEG Video Decoder,0x40000001,1,1,quartz.dll,10.00.19041.5856 + +WDM Streaming Tee/Splitter Devices: +Tee/Sink-to-Sink Converter,0x00200000,1,1,ksproxy.ax,10.00.19041.5794 + +Video Compressors: +WMVideo8 Encoder DMO,0x00600800,1,1,wmvxencd.dll,10.00.19041.6093 +WMVideo9 Encoder DMO,0x00600800,1,1,wmvencod.dll,10.00.19041.6093 +MSScreen 9 encoder DMO,0x00600800,1,1,wmvsencd.dll,10.00.19041.6093 +DV Video Encoder,0x00200000,0,0,qdv.dll,10.00.19041.0001 +MJPEG Compressor,0x00200000,0,0,quartz.dll,10.00.19041.5856 + +Audio Compressors: +WM Speech Encoder DMO,0x00600800,1,1,WMSPDMOE.DLL,10.00.19041.6093 +WMAudio Encoder DMO,0x00600800,1,1,WMADMOE.DLL,10.00.19041.6093 +IMA ADPCM,0x00200000,1,1,quartz.dll,10.00.19041.5856 +PCM,0x00200000,1,1,quartz.dll,10.00.19041.5856 +Microsoft ADPCM,0x00200000,1,1,quartz.dll,10.00.19041.5856 +GSM 6.10,0x00200000,1,1,quartz.dll,10.00.19041.5856 +CCITT A-Law,0x00200000,1,1,quartz.dll,10.00.19041.5856 +CCITT u-Law,0x00200000,1,1,quartz.dll,10.00.19041.5856 +MPEG Layer-3,0x00200000,1,1,quartz.dll,10.00.19041.5856 + +PBDA CP Filters: +PBDA DTFilter,0x00600000,1,1,CPFilters.dll,10.00.19041.6456 +PBDA ETFilter,0x00200000,0,0,CPFilters.dll,10.00.19041.6456 +PBDA PTFilter,0x00200000,0,0,CPFilters.dll,10.00.19041.6456 + +Midi Renderers: +Default MidiOut Device,0x00800000,1,0,quartz.dll,10.00.19041.5856 +Microsoft GS Wavetable Synth,0x00200000,1,0,quartz.dll,10.00.19041.5856 + +WDM Streaming Capture Devices: +,0x00000000,0,0,, +,0x00000000,0,0,, +Realtek HD Audio Mic input,0x00200000,1,1,ksproxy.ax,10.00.19041.5794 +Realtek HD Audio Stereo input,0x00200000,1,1,ksproxy.ax,10.00.19041.5794 + +WDM Streaming Rendering Devices: +Realtek HD Audio 2nd output,0x00200000,1,1,ksproxy.ax,10.00.19041.5794 +Realtek HDA Primary output,0x00200000,1,1,ksproxy.ax,10.00.19041.5794 +Realtek HDA SPDIF Out,0x00200000,1,1,ksproxy.ax,10.00.19041.5794 +,0x00000000,0,0,, +,0x00000000,0,0,, + +BDA Network Providers: +Microsoft ATSC Network Provider,0x00200000,0,1,MSDvbNP.ax,10.00.19041.0001 +Microsoft DVBC Network Provider,0x00200000,0,1,MSDvbNP.ax,10.00.19041.0001 +Microsoft DVBS Network Provider,0x00200000,0,1,MSDvbNP.ax,10.00.19041.0001 +Microsoft DVBT Network Provider,0x00200000,0,1,MSDvbNP.ax,10.00.19041.0001 +Microsoft Network Provider,0x00200000,0,1,MSNP.ax,10.00.19041.0001 + +Multi-Instance Capable VBI Codecs: +VBI Codec,0x00600000,1,4,VBICodec.ax,10.00.19041.3636 + +BDA Transport Information Renderers: +BDA MPEG2 Transport Information Filter,0x00600000,2,0,psisrndr.ax,10.00.19041.0001 +MPEG-2 Sections and Tables,0x00600000,1,0,Mpeg2Data.ax,10.00.19041.0001 + +WDM Streaming Communication Transforms: +Tee/Sink-to-Sink Converter,0x00200000,1,1,ksproxy.ax,10.00.19041.5794 + +Audio Renderers: +Remote Audio,0x00200000,1,0,quartz.dll,10.00.19041.5856 +Default DirectSound Device,0x00800000,1,0,quartz.dll,10.00.19041.5856 +Default WaveOut Device,0x00200000,1,0,quartz.dll,10.00.19041.5856 +DirectSound: Remote Audio,0x00200000,1,0,quartz.dll,10.00.19041.5856 + + +---------------------------- +Preferred DirectShow Filters +---------------------------- + +[HKEY_LOCAL_MACHINE\Software\Microsoft\DirectShow\Preferred] + +, [, ] + +MEDIASUBTYPE_DVD_LPCM_AUDIO, Microsoft DTV-DVD Audio Decoder, CLSID_CMPEG2AudDecoderDS +MEDIASUBTYPE_MPEG2_AUDIO, Microsoft DTV-DVD Audio Decoder, CLSID_CMPEG2AudDecoderDS +MEDIASUBTYPE_MPEG2_VIDEO, Microsoft DTV-DVD Video Decoder, CLSID_CMPEG2VidDecoderDS +{78766964-0000-0010-8000-00AA00389B71}, Mpeg4s Decoder DMO, CLSID_CMpeg4sDecMediaObject +{7634706D-0000-0010-8000-00AA00389B71}, Mpeg4s Decoder DMO, CLSID_CMpeg4sDecMediaObject +MEDIASUBTYPE_mp4s, Mpeg4s Decoder DMO, CLSID_CMpeg4sDecMediaObject +{64697678-0000-0010-8000-00AA00389B71}, Mpeg4s Decoder DMO, CLSID_CMpeg4sDecMediaObject +{58564944-0000-0010-8000-00AA00389B71}, Mpeg4s Decoder DMO, CLSID_CMpeg4sDecMediaObject +{5634504D-0000-0010-8000-00AA00389B71}, Mpeg4s Decoder DMO, CLSID_CMpeg4sDecMediaObject +MEDIASUBTYPE_MP4S, Mpeg4s Decoder DMO, CLSID_CMpeg4sDecMediaObject +MEDIASUBTYPE_WMVR, WMVideo Decoder DMO, CLSID_CWMVDecMediaObject +MEDIASUBTYPE_WMVP, WMVideo Decoder DMO, CLSID_CWMVDecMediaObject +{44495658-0000-0010-8000-00AA00389B71}, Mpeg4s Decoder DMO, CLSID_CMpeg4sDecMediaObject +MEDIASUBTYPE_WMVA, WMVideo Decoder DMO, CLSID_CWMVDecMediaObject +MEDIASUBTYPE_mpg4, Mpeg4 Decoder DMO, CLSID_CMpeg4DecMediaObject +MEDIASUBTYPE_MPG4, Mpeg4 Decoder DMO, CLSID_CMpeg4DecMediaObject +MEDIASUBTYPE_h264, Microsoft DTV-DVD Video Decoder, CLSID_CMPEG2VidDecoderDS +MEDIASUBTYPE_H264, Microsoft DTV-DVD Video Decoder, CLSID_CMPEG2VidDecoderDS +MEDIASUBTYPE_WMV3, WMVideo Decoder DMO, CLSID_CWMVDecMediaObject +MEDIASUBTYPE_mp43, Mpeg43 Decoder DMO, CLSID_CMpeg43DecMediaObject +MEDIASUBTYPE_MP43, Mpeg43 Decoder DMO, CLSID_CMpeg43DecMediaObject +MEDIASUBTYPE_m4s2, Mpeg4s Decoder DMO, CLSID_CMpeg4sDecMediaObject +MEDIASUBTYPE_WMV2, WMVideo Decoder DMO, CLSID_CWMVDecMediaObject +MEDIASUBTYPE_MSS2, WMV Screen decoder DMO, CLSID_CMSSCDecMediaObject +MEDIASUBTYPE_M4S2, Mpeg4s Decoder DMO, CLSID_CMpeg4sDecMediaObject +MEDIASUBTYPE_WVP2, WMVideo Decoder DMO, CLSID_CWMVDecMediaObject +MEDIASUBTYPE_mp42, Mpeg4 Decoder DMO, CLSID_CMpeg4DecMediaObject +MEDIASUBTYPE_MP42, Mpeg4 Decoder DMO, CLSID_CMpeg4DecMediaObject +MEDIASUBTYPE_WMV1, WMVideo Decoder DMO, CLSID_CWMVDecMediaObject +MEDIASUBTYPE_MSS1, WMV Screen decoder DMO, CLSID_CMSSCDecMediaObject +MEDIASUBTYPE_WVC1, WMVideo Decoder DMO, CLSID_CWMVDecMediaObject +MEDIASUBTYPE_AVC1, Microsoft DTV-DVD Video Decoder, CLSID_CMPEG2VidDecoderDS +MEDIASUBTYPE_MPEG_LOAS, Microsoft DTV-DVD Audio Decoder, CLSID_CMPEG2AudDecoderDS +MEDIASUBTYPE_MPEG_ADTS_AAC, Microsoft DTV-DVD Audio Decoder, CLSID_CMPEG2AudDecoderDS +MEDIASUBTYPE_WMAUDIO_LOSSLESS, WMAudio Decoder DMO, CLSID_CWMADecMediaObject +MEDIASUBTYPE_WMAUDIO3, WMAudio Decoder DMO, CLSID_CWMADecMediaObject +WMMEDIASUBTYPE_WMAudioV8, WMAudio Decoder DMO, CLSID_CWMADecMediaObject +MEDIASUBTYPE_MSAUDIO1, WMAudio Decoder DMO, CLSID_CWMADecMediaObject +MEDIASUBTYPE_RAW_AAC1, Microsoft DTV-DVD Audio Decoder, CLSID_CMPEG2AudDecoderDS +WMMEDIASUBTYPE_MP3, MP3 Decoder DMO, CLSID_CMP3DecMediaObject +MEDIASUBTYPE_MPEG1Payload, MPEG Video Decoder, CLSID_CMpegVideoCodec +MEDIASUBTYPE_MPEG1Packet, MPEG Video Decoder, CLSID_CMpegVideoCodec +{6C737664-0000-0010-8000-00AA00389B71}, DV Video Decoder, CLSID_DVVideoCodec +{64737664-0000-0010-8000-00AA00389B71}, DV Video Decoder, CLSID_DVVideoCodec +{64687664-0000-0010-8000-00AA00389B71}, DV Video Decoder, CLSID_DVVideoCodec +MEDIASUBTYPE_MJPG, MJPEG Decompressor, CLSID_MjpegDec +{20637664-0000-0010-8000-00AA00389B71}, DV Video Decoder, CLSID_DVVideoCodec +MEDIASUBTYPE_MPEG1AudioPayload, MPEG Audio Decoder, CLSID_CMpegAudioCodec +WMMEDIASUBTYPE_WMSP2, WMSpeech Decoder DMO, CLSID_CWMSPDecMediaObject +WMMEDIASUBTYPE_WMSP1, WMSpeech Decoder DMO, CLSID_CWMSPDecMediaObject + + +--------------------------- +Media Foundation File Versions +--------------------------- + + mfcore.dll, 10.00.19041.6456 + mfreadwrite.dll, 10.00.19041.6033 + mfcaptureengine.dll, 10.00.19041.5794 + mfsensorgroup.dll, 10.00.19041.5854 + windows.media.dll, 10.00.19041.5794 + frameserver.dll, 10.00.19041.5854 + frameserverclient.dll, 10.00.19041.5854 + + +--------------------------- +Media Foundation Transforms +--------------------------- + +[HKEY_LOCAL_MACHINE\Software\Classes\MediaFoundation\Transforms] + +: + , , , [, ], + +Video Decoders: + Intel Hardware M-JPEG Decoder MFT, {00C69F81-0524-48C0-A353-4DD9D54F9A6E}, 0x6, 7, mfx_mft_mjpgvd_64.dll, 24.10.0012.0001 + NVIDIA MJPEG Video Decoder MFT, {70F36578-2741-454F-B494-E8563DDD1CB4}, 0x4, 8, nvDecMFTMjpegx.dll, 32.00.0015.7688 + Microsoft MPEG Video Decoder MFT, {2D709E52-123F-49B5-9CBC-9AF5CDE28FB9}, 0x1, msmpeg2vdec.dll, 10.00.19041.6456 + DV Decoder MFT, {404A6DE5-D4D6-4260-9BC7-5A6CBD882432}, 0x1, mfdvdec.dll, 10.00.19041.0001 + Mpeg4s Decoder MFT, CLSID_CMpeg4sDecMFT, 0x1, mp4sdecd.dll, 10.00.19041.6093 + Microsoft H264 Video Decoder MFT, CLSID_CMSH264DecoderMFT, 0x1, msmpeg2vdec.dll, 10.00.19041.6456 + WMV Screen decoder MFT, CLSID_CMSSCDecMediaObject, 0x1, wmvsdecd.dll, 10.00.19041.6093 + WMVideo Decoder MFT, CLSID_CWMVDecMediaObject, 0x1, wmvdecod.dll, 10.00.19041.6456 + MJPEG Decoder MFT, {CB17E772-E1CC-4633-8450-5617AF577905}, 0x1, mfmjpegdec.dll, 10.00.19041.5856 + Mpeg43 Decoder MFT, CLSID_CMpeg43DecMediaObject, 0x1, mp43decd.dll, 10.00.19041.3636 + MS ATC Screen Decoder 1, {F1931D8E-51D3-496F-BE8A-3D08AEE9C9DB}, 0x1, scdec.dll, 15.00.4703.1000 + Mpeg4 Decoder MFT, CLSID_CMpeg4DecMediaObject, 0x1, mpg4decd.dll, 10.00.19041.3636 + WebpImageExtension + VP9VideoExtensionDecoder + HEIFImageExtension +Video Encoders: + NVIDIA HEVC Encoder MFT, {362A74CD-E177-4916-A569-C3D4D99CE786}, 0x4, 8, nvEncMFThevcx.dll, 32.00.0015.7688 + Intel Quick Sync Video H.264 Encoder MFT, {4BE8D3C0-0515-4A37-AD55-E4BAE19AF471}, 0x4, 7, mfx_mft_h264ve_64.dll, 24.10.0012.0001 + NVIDIA H.264 Encoder MFT, {60F44560-5A20-4857-BFEF-D29773CB8040}, 0x4, 8, nvEncMFTH264x.dll, 32.00.0015.7688 + NVIDIA AV1 Encoder MFT, {80B80715-8C5A-420D-B346-1A9DC40A5880}, 0x4, 8, nvEncMFTav1x.dll, 32.00.0015.7688 + Intel Hardware H265 Encoder MFT, {BC10864D-2B34-408F-912A-102B1B867B6C}, 0x4, 7, mfx_mft_h265ve_64.dll, 24.10.0012.0001 + Intel Hardware VP9 Encoder MFT, {D186A626-77CA-4D80-942F-61E0A5111AFE}, 0x4, 7, mfx_mft_vp9ve_64.dll, 24.10.0012.0001 + H264 Encoder MFT, {6CA50344-051A-4DED-9779-A43305165E35}, 0x1, mfh264enc.dll, 10.00.19041.6093 + WMVideo8 Encoder MFT, CLSID_CWMVXEncMediaObject, 0x1, wmvxencd.dll, 10.00.19041.6093 + H263 Encoder MFT, {BC47FCFE-98A0-4F27-BB07-698AF24F2B38}, 0x1, mfh263enc.dll, 10.00.19041.0001 + WMVideo9 Encoder MFT, CLSID_CWMV9EncMediaObject, 0x1, wmvencod.dll, 10.00.19041.6093 + Microsoft MPEG-2 Video Encoder MFT, {E6335F02-80B7-4DC4-ADFA-DFE7210D20D5}, 0x2, msmpeg2enc.dll, 10.00.19041.6093 + VP9VideoExtensionEncoder + HEIFImageExtension +Video Effects: + Frame Rate Converter, CLSID_CFrameRateConvertDmo, 0x1, mfvdsp.dll, 10.00.19041.3636 + Resizer MFT, CLSID_CResizerDMO, 0x1, vidreszr.dll, 10.00.19041.6093 + VideoStabilization MFT, {51571744-7FE4-4FF2-A498-2DC34FF74F1B}, 0x1, MSVideoDSP.dll, 10.00.19041.3636 + Color Control, CLSID_CColorControlDmo, 0x1, mfvdsp.dll, 10.00.19041.3636 + Color Converter MFT, CLSID_CColorConvertDMO, 0x1, colorcnv.dll, 10.00.19041.6093 +Video Processor: + Microsoft Video Processor MFT, {88753B26-5B24-49BD-B2E7-0C445C78C982}, 0x1, msvproc.dll, 10.00.19041.5794 +Audio Decoders: + Microsoft Dolby Digital Plus Decoder MFT, {177C0AFE-900B-48D4-9E4C-57ADD250B3D4}, 0x1, DolbyDecMFT.dll, 10.00.19041.6456 + MS AMRNB Decoder MFT, {265011AE-5481-4F77-A295-ABB6FFE8D63E}, 0x1, MSAMRNBDecoder.dll, 10.00.19041.0001 + WMAudio Decoder MFT, CLSID_CWMADecMediaObject, 0x1, WMADMOD.DLL, 10.00.19041.6093 + Microsoft AAC Audio Decoder MFT, CLSID_CMSAACDecMFT, 0x1, MSAudDecMFT.dll, 10.00.19041.6093 + A-law Wrapper MFT, {36CB6E0C-78C1-42B2-9943-846262F31786}, 0x1, mfcore.dll, 10.00.19041.6456 + GSM ACM Wrapper MFT, {4A76B469-7B66-4DD4-BA2D-DDF244C766DC}, 0x1, mfcore.dll, 10.00.19041.6456 + WMAPro over S/PDIF MFT, CLSID_CWMAudioSpdTxDMO, 0x1, WMADMOD.DLL, 10.00.19041.6093 + Microsoft Opus Audio Decoder MFT, {63E17C10-2D43-4C42-8FE3-8D8B63E46A6A}, 0x1, MSOpusDecoder.dll, 10.00.19041.3636 + Microsoft FLAC Audio Decoder MFT, {6B0B3E6B-A2C5-4514-8055-AFE8A95242D9}, 0x1, MSFlacDecoder.dll, 10.00.19041.4355 + Microsoft MPEG Audio Decoder MFT, {70707B39-B2CA-4015-ABEA-F8447D22D88B}, 0x1, MSAudDecMFT.dll, 10.00.19041.6093 + WMSpeech Decoder DMO, CLSID_CWMSPDecMediaObject, 0x1, WMSPDMOD.DLL, 10.00.19041.0001 + G711 Wrapper MFT, {92B66080-5E2D-449E-90C4-C41F268E5514}, 0x1, mfcore.dll, 10.00.19041.6456 + IMA ADPCM ACM Wrapper MFT, {A16E1BFF-A80D-48AD-AECD-A35C005685FE}, 0x1, mfcore.dll, 10.00.19041.6456 + MP3 Decoder MFT, CLSID_CMP3DecMediaObject, 0x1, mp3dmod.dll, 10.00.19041.0001 + Microsoft ALAC Audio Decoder MFT, {C0CD7D12-31FC-4BBC-B363-7322EE3E1879}, 0x1, MSAlacDecoder.dll, 10.00.19041.3636 + ADPCM ACM Wrapper MFT, {CA34FE0A-5722-43AD-AF23-05F7650257DD}, 0x1, mfcore.dll, 10.00.19041.6456 + Dolby TrueHD IEC-61937 converter MFT, {CF5EEEDF-0E92-4B3B-A161-BD0FFE545E4B}, 0x1, mfaudiocnv.dll, 10.00.19041.6456 + DTS IEC-61937 converter MFT, {D035E24C-C877-42D7-A795-2A8A339B472F}, 0x1, mfaudiocnv.dll, 10.00.19041.6456 +Audio Encoders: + LPCM DVD-Audio MFT, {068A8476-9229-4CC0-9D49-2FC699DCD30A}, 0x1, mfaudiocnv.dll, 10.00.19041.6456 + MP3 Encoder ACM Wrapper MFT, {11103421-354C-4CCA-A7A3-1AFF9A5B6701}, 0x1, mfcore.dll, 10.00.19041.6456 + Microsoft FLAC Audio Encoder MFT, {128509E9-C44E-45DC-95E9-C255B8F466A6}, 0x1, MSFlacEncoder.dll, 10.00.19041.4355 + WM Speech Encoder DMO, CLSID_CWMSPEncMediaObject2, 0x1, WMSPDMOE.DLL, 10.00.19041.6093 + MS AMRNB Encoder MFT, {2FAE8AFE-04A3-423A-A814-85DB454712B0}, 0x1, MSAMRNBEncoder.dll, 10.00.19041.0001 + Microsoft MPEG-2 Audio Encoder MFT, {46A4DD5C-73F8-4304-94DF-308F760974F4}, 0x1, msmpeg2enc.dll, 10.00.19041.6093 + WMAudio Encoder MFT, CLSID_CWMAEncMediaObject, 0x1, WMADMOE.DLL, 10.00.19041.6093 + Microsoft AAC Audio Encoder MFT, {93AF0C51-2275-45D2-A35B-F2BA21CAED00}, 0x1, mfAACEnc.dll, 10.00.19041.0001 + Microsoft ALAC Audio Encoder MFT, {9AB6A28C-748E-4B6A-BFFF-CC443B8E8FB4}, 0x1, MSAlacEncoder.dll, 10.00.19041.3636 + Microsoft Dolby Digital Encoder MFT, {AC3315C9-F481-45D7-826C-0B406C1F64B8}, 0x1, msac3enc.dll, 10.00.19041.0001 +Audio Effects: + AEC, CLSID_CWMAudioAEC, 0x1, mfwmaaec.dll, 10.00.19041.0001 + Resampler MFT, CLSID_CResamplerMediaObject, 0x1, resampledmo.dll, 10.00.19041.0001 +Multiplexers: + Microsoft MPEG2 Multiplexer MFT, {AB300F71-01AB-46D2-AB6C-64906CB03258}, 0x2, mfmpeg2srcsnk.dll, 10.00.19041.6392 +Others: + Microsoft H264 Video Remux (MPEG2TSToMP4) MFT, {05A47EBB-8BF0-4CBF-AD2F-3B71D75866F5}, 0x1, msmpeg2vdec.dll, 10.00.19041.6456 + + +-------------------------------------------- +Media Foundation Enabled Hardware Categories +-------------------------------------------- + +[HKEY_LOCAL_MACHINE\Software\Microsoft\Windows Media Foundation\HardwareMFT] + +EnableDecoders = 1 +EnableEncoders = 1 + + +------------------------------------- +Media Foundation Byte Stream Handlers +------------------------------------- + +[HKEY_LOCAL_MACHINE\Software\Microsoft\Windows Media Foundation\ByteStreamHandlers] +[HKEY_LOCAL_MACHINE\Software\Classes\MediaFoundation\MediaSources\Preferred] + +, , [, Preferred] + +.3g2, {271C3902-6095-4C45-A22F-20091816EE9E}, MPEG4 Byte Stream Handler, Preferred +.3gp, {271C3902-6095-4C45-A22F-20091816EE9E}, MPEG4 Byte Stream Handler, Preferred +.3gp2, {271C3902-6095-4C45-A22F-20091816EE9E}, MPEG4 Byte Stream Handler, Preferred +.3gpp, {271C3902-6095-4C45-A22F-20091816EE9E}, MPEG4 Byte Stream Handler, Preferred +.aac, {926F41F7-003E-4382-9E84-9E953BE10562}, ADTS Byte Stream Handler, Preferred +.ac3, {46031BA1-083F-47D9-8369-23C92BDAB2FF}, AC-3 Byte Stream Handler, Preferred +.adt, {926F41F7-003E-4382-9E84-9E953BE10562}, ADTS Byte Stream Handler, Preferred +.adts, {926F41F7-003E-4382-9E84-9E953BE10562}, ADTS Byte Stream Handler, Preferred +.am?, {EFE6208A-0A2C-49FA-8A01-3768B559B6DA}, MF AMRNB Media Source ByteStreamHandler +.amr, {EFE6208A-0A2C-49FA-8A01-3768B559B6DA}, MF AMRNB Media Source ByteStreamHandler, Preferred +.asf, {41457294-644C-4298-A28A-BD69F2C0CF3B}, ASF Byte Stream Handler, Preferred +.avi, {7AFA253E-F823-42F6-A5D9-714BDE467412}, AVI Byte Stream Handler, Preferred +.dvr-ms, {A8721937-E2FB-4D7A-A9EE-4EB08C890B6E}, MF SBE Source ByteStreamHandler +.dvr-ms, {65964407-A5D8-4060-85B0-1CCD63F768E2}, dvr-ms Byte Stream Handler, Preferred +.ec3, {46031BA1-083F-47D9-8369-23C92BDAB2FF}, AC-3 Byte Stream Handler, Preferred +.flac, {0E41CFB8-0506-40F4-A516-77CC23642D91}, MF FLAC Media Source ByteStreamHandler, Preferred +.m2t, {40871C59-AB40-471F-8DC3-1F259D862479}, MPEG2 Byte Stream Handler, Preferred +.m2ts, {40871C59-AB40-471F-8DC3-1F259D862479}, MPEG2 Byte Stream Handler, Preferred +.m4a, {271C3902-6095-4C45-A22F-20091816EE9E}, MPEG4 Byte Stream Handler, Preferred +.m4v, {271C3902-6095-4C45-A22F-20091816EE9E}, MPEG4 Byte Stream Handler, Preferred +.mk3d, {1F9A2C18-D89E-463E-B4F4-BB90152ACC64}, MKV Byte Stream Handler, Preferred +.mka, {1F9A2C18-D89E-463E-B4F4-BB90152ACC64}, MKV Byte Stream Handler, Preferred +.mks, {1F9A2C18-D89E-463E-B4F4-BB90152ACC64}, MKV Byte Stream Handler, Preferred +.mkv, {1F9A2C18-D89E-463E-B4F4-BB90152ACC64}, MKV Byte Stream Handler, Preferred +.mod, {40871C59-AB40-471F-8DC3-1F259D862479}, MPEG2 Byte Stream Handler, Preferred +.mov, {271C3902-6095-4C45-A22F-20091816EE9E}, MPEG4 Byte Stream Handler, Preferred +.mp2v, {40871C59-AB40-471F-8DC3-1F259D862479}, MPEG2 Byte Stream Handler, Preferred +.mp3, {A82E50BA-8E92-41EB-9DF2-433F50EC2993}, MP3 Byte Stream Handler, Preferred +.mp4, {271C3902-6095-4C45-A22F-20091816EE9E}, MPEG4 Byte Stream Handler, Preferred +.mp4v, {271C3902-6095-4C45-A22F-20091816EE9E}, MPEG4 Byte Stream Handler, Preferred +.mpa, {A82E50BA-8E92-41EB-9DF2-433F50EC2993}, MP3 Byte Stream Handler, Preferred +.mpeg, {40871C59-AB40-471F-8DC3-1F259D862479}, MPEG2 Byte Stream Handler, Preferred +.mpg, {40871C59-AB40-471F-8DC3-1F259D862479}, MPEG2 Byte Stream Handler, Preferred +.mts, {40871C59-AB40-471F-8DC3-1F259D862479}, MPEG2 Byte Stream Handler, Preferred +.nsc, {B084785C-DDE0-4D30-8CA8-05A373E185BE}, NSC Byte Stream Handler, Preferred +.sami, {7A56C4CB-D678-4188-85A8-BA2EF68FA10D}, SAMI Byte Stream Handler, Preferred +.smi, {7A56C4CB-D678-4188-85A8-BA2EF68FA10D}, SAMI Byte Stream Handler, Preferred +.tod, {40871C59-AB40-471F-8DC3-1F259D862479}, MPEG2 Byte Stream Handler, Preferred +.ts, {40871C59-AB40-471F-8DC3-1F259D862479}, MPEG2 Byte Stream Handler, Preferred +.tts, {40871C59-AB40-471F-8DC3-1F259D862479}, MPEG2 Byte Stream Handler, Preferred +.uvu, {271C3902-6095-4C45-A22F-20091816EE9E}, MPEG4 Byte Stream Handler, Preferred +.vob, {40871C59-AB40-471F-8DC3-1F259D862479}, MPEG2 Byte Stream Handler, Preferred +.wav, {42C9B9F5-16FC-47EF-AF22-DA05F7C842E3}, WAV Byte Stream Handler, Preferred +.weba, {1F9A2C18-D89E-463E-B4F4-BB90152ACC64}, WEBM Byte Stream Handler, Preferred +.webm, {1F9A2C18-D89E-463E-B4F4-BB90152ACC64}, WEBM Byte Stream Handler, Preferred +.wm, {41457294-644C-4298-A28A-BD69F2C0CF3B}, ASF Byte Stream Handler, Preferred +.wma, {41457294-644C-4298-A28A-BD69F2C0CF3B}, ASF Byte Stream Handler, Preferred +.wmv, {41457294-644C-4298-A28A-BD69F2C0CF3B}, ASF Byte Stream Handler, Preferred +.wtv, {65964407-A5D8-4060-85B0-1CCD63F768E2}, WTV Byte Stream Handler, Preferred +audio/3gpp, {271C3902-6095-4C45-A22F-20091816EE9E}, MPEG4 Byte Stream Handler, Preferred +audio/3gpp2, {271C3902-6095-4C45-A22F-20091816EE9E}, MPEG4 Byte Stream Handler, Preferred +audio/aac, {926F41F7-003E-4382-9E84-9E953BE10562}, ADTS Byte Stream Handler, Preferred +audio/aacp, {926F41F7-003E-4382-9E84-9E953BE10562}, ADTS Byte Stream Handler, Preferred +audio/eac3, {46031BA1-083F-47D9-8369-23C92BDAB2FF}, AC-3 Byte Stream Handler, Preferred +audio/flac, {0E41CFB8-0506-40F4-A516-77CC23642D91}, MF FLAC Media Source ByteStreamHandler, Preferred +audio/L16, {3FFB3B8C-EB99-472B-8902-E1C1B05F07CF}, LPCM Byte Stream Handler, Preferred +audio/mp3, {A82E50BA-8E92-41EB-9DF2-433F50EC2993}, MP3 Byte Stream Handler, Preferred +audio/mp4, {271C3902-6095-4C45-A22F-20091816EE9E}, MPEG4 Byte Stream Handler, Preferred +audio/MP4A-LATM, {271C3902-6095-4C45-A22F-20091816EE9E}, MPEG4 Byte Stream Handler, Preferred +audio/mpa, {A82E50BA-8E92-41EB-9DF2-433F50EC2993}, MP3 Byte Stream Handler, Preferred +audio/mpeg, {A82E50BA-8E92-41EB-9DF2-433F50EC2993}, MP3 Byte Stream Handler, Preferred +audio/mpeg3, {A82E50BA-8E92-41EB-9DF2-433F50EC2993}, MP3 Byte Stream Handler, Preferred +audio/vnd.dlna.adts, {926F41F7-003E-4382-9E84-9E953BE10562}, ADTS Byte Stream Handler, Preferred +audio/vnd.dolby.dd-raw, {46031BA1-083F-47D9-8369-23C92BDAB2FF}, AC-3 Byte Stream Handler, Preferred +audio/wav, {42C9B9F5-16FC-47EF-AF22-DA05F7C842E3}, WAV Byte Stream Handler, Preferred +audio/webm, {1F9A2C18-D89E-463E-B4F4-BB90152ACC64}, WEBM Byte Stream Handler, Preferred +audio/x-aac, {926F41F7-003E-4382-9E84-9E953BE10562}, ADTS Byte Stream Handler, Preferred +audio/x-flac, {0E41CFB8-0506-40F4-A516-77CC23642D91}, MF FLAC Media Source ByteStreamHandler, Preferred +audio/x-m4a, {271C3902-6095-4C45-A22F-20091816EE9E}, MPEG4 Byte Stream Handler, Preferred +audio/x-matroska, {1F9A2C18-D89E-463E-B4F4-BB90152ACC64}, MKV Byte Stream Handler, Preferred +audio/x-mp3, {A82E50BA-8E92-41EB-9DF2-433F50EC2993}, MP3 Byte Stream Handler, Preferred +audio/x-mpeg, {A82E50BA-8E92-41EB-9DF2-433F50EC2993}, MP3 Byte Stream Handler, Preferred +audio/x-ms-wma, {41457294-644C-4298-A28A-BD69F2C0CF3B}, ASF Byte Stream Handler, Preferred +audio/x-wav, {42C9B9F5-16FC-47EF-AF22-DA05F7C842E3}, WAV Byte Stream Handler, Preferred +video/3gpp, {271C3902-6095-4C45-A22F-20091816EE9E}, MPEG4 Byte Stream Handler, Preferred +video/3gpp2, {271C3902-6095-4C45-A22F-20091816EE9E}, MPEG4 Byte Stream Handler, Preferred +video/avi, {7AFA253E-F823-42F6-A5D9-714BDE467412}, AVI Byte Stream Handler, Preferred +video/mp4, {271C3902-6095-4C45-A22F-20091816EE9E}, MPEG4 Byte Stream Handler, Preferred +video/mpeg, {40871C59-AB40-471F-8DC3-1F259D862479}, MPEG2 Byte Stream Handler, Preferred +video/msvideo, {7AFA253E-F823-42F6-A5D9-714BDE467412}, AVI Byte Stream Handler, Preferred +video/vnd.dece.mp4, {271C3902-6095-4C45-A22F-20091816EE9E}, MPEG4 Byte Stream Handler, Preferred +video/vnd.dlna.mpeg-tts, {40871C59-AB40-471F-8DC3-1F259D862479}, MPEG2 Byte Stream Handler, Preferred +video/webm, {1F9A2C18-D89E-463E-B4F4-BB90152ACC64}, WEBM Byte Stream Handler, Preferred +video/x-m4v, {271C3902-6095-4C45-A22F-20091816EE9E}, MPEG4 Byte Stream Handler, Preferred +video/x-matroska, {1F9A2C18-D89E-463E-B4F4-BB90152ACC64}, MKV Byte Stream Handler, Preferred +video/x-ms-asf, {41457294-644C-4298-A28A-BD69F2C0CF3B}, ASF Byte Stream Handler, Preferred +video/x-ms-wm, {41457294-644C-4298-A28A-BD69F2C0CF3B}, ASF Byte Stream Handler, Preferred +video/x-ms-wmv, {41457294-644C-4298-A28A-BD69F2C0CF3B}, ASF Byte Stream Handler, Preferred +video/x-msvideo, {7AFA253E-F823-42F6-A5D9-714BDE467412}, AVI Byte Stream Handler, Preferred + + +-------------------------------- +Media Foundation Scheme Handlers +-------------------------------- + +[HKEY_LOCAL_MACHINE\Software\Microsoft\Windows Media Foundation\SchemeHandlers] +[HKEY_LOCAL_MACHINE\Software\Classes\MediaFoundation\MediaSources\Preferred] + +, , [, Preferred] + +file:, {477EC299-1421-4BDD-971F-7CCB933F21AD}, File Scheme Handler, Preferred +http:, {44CB442B-9DA9-49DF-B3FD-023777B16E50}, Http Scheme Handler +http:, {9EC4B4F9-3029-45AD-947B-344DE2A249E2}, Urlmon Scheme Handler +http:, {E9F4EBAB-D97B-463E-A2B1-C54EE3F9414D}, Net Scheme Handler, Preferred +httpd:, {44CB442B-9DA9-49DF-B3FD-023777B16E50}, Http Scheme Handler, Preferred +https:, {37A61C8B-7F8E-4D08-B12B-248D73E9AB4F}, Secure Http Scheme Handler, Preferred +httpsd:, {37A61C8B-7F8E-4D08-B12B-248D73E9AB4F}, Secure Http Scheme Handler, Preferred +httpt:, {E9F4EBAB-D97B-463E-A2B1-C54EE3F9414D}, Net Scheme Handler, Preferred +httpu:, {E9F4EBAB-D97B-463E-A2B1-C54EE3F9414D}, Net Scheme Handler, Preferred +mcast:, {E9F4EBAB-D97B-463E-A2B1-C54EE3F9414D}, Net Scheme Handler, Preferred +mcrecv:, {FA6D33D4-9405-4BA5-9983-12604AC8E77A}, Miracast Sink Scheme Handler, Preferred +mms:, {E9F4EBAB-D97B-463E-A2B1-C54EE3F9414D}, Net Scheme Handler, Preferred +ms-appdata:, {CFC81939-3886-4ACF-9692-DA58037AE716}, MsAppData Scheme Handler, Preferred +ms-appx-web:, {8DB0224B-3D65-4F6F-8E12-BEB4B78B8974}, MsAppxWeb Scheme Handler, Preferred +ms-appx:, {8DB0224B-3D65-4F6F-8E12-BEB4B78B8974}, MsAppx Scheme Handler, Preferred +ms-winsoundevent:, {F79A6BF9-7415-4CF3-AE10-4559509ABC3C}, Sound Event Scheme Handler, Preferred +rtsp:, {E9F4EBAB-D97B-463E-A2B1-C54EE3F9414D}, Net Scheme Handler, Preferred +rtsps:, {E9F4EBAB-D97B-463E-A2B1-C54EE3F9414D}, Net Scheme Handler, Preferred +rtspt:, {E9F4EBAB-D97B-463E-A2B1-C54EE3F9414D}, Net Scheme Handler, Preferred +rtspu:, {E9F4EBAB-D97B-463E-A2B1-C54EE3F9414D}, Net Scheme Handler, Preferred +sdp:, {E9F4EBAB-D97B-463E-A2B1-C54EE3F9414D}, Net Scheme Handler, Preferred + + +------------------------------------- +Preferred Media Foundation Transforms +------------------------------------- + +[HKEY_LOCAL_MACHINE\Software\Classes\MediaFoundation\Transforms\Preferred] + +, [, ] + +{EB27CEC4-163E-4CA3-8B74-8E25F91B517E}, Dolby TrueHD IEC-61937 converter MFT, {CF5EEEDF-0E92-4B3B-A161-BD0FFE545E4B} +{E06D802C-DB46-11CF-B4D1-00805F6CBBEA}, Microsoft Dolby Digital Plus Decoder MFT, {177C0AFE-900B-48D4-9E4C-57ADD250B3D4} +MFVideoFormat_MPEG2, Microsoft MPEG Video Decoder MFT, {2D709E52-123F-49B5-9CBC-9AF5CDE28FB9} +MEDIASUBTYPE_DOLBY_DDPLUS, Microsoft Dolby Digital Plus Decoder MFT, {177C0AFE-900B-48D4-9E4C-57ADD250B3D4} +{A61AC364-AD0E-4744-89FF-213CE0DF8804}, DTS IEC-61937 converter MFT, {D035E24C-C877-42D7-A795-2A8A339B472F} +{A2E58EB7-0FA9-48BB-A40C-FA0E156D0645}, DTS IEC-61937 converter MFT, {D035E24C-C877-42D7-A795-2A8A339B472F} +{7634706D-0000-0010-8000-00AA00389B71}, Mpeg4s Decoder MFT, CLSID_CMpeg4sDecMFT +{73616D72-767A-494D-B478-F29D25DC9037}, MS AMRNB Decoder MFT, {265011AE-5481-4F77-A295-ABB6FFE8D63E} +MEDIASUBTYPE_mp4s, Mpeg4s Decoder MFT, CLSID_CMpeg4sDecMFT +MFVideoFormat_DVSL, DV Decoder MFT, {404A6DE5-D4D6-4260-9BC7-5A6CBD882432} +MFVideoFormat_DVSD, DV Decoder MFT, {404A6DE5-D4D6-4260-9BC7-5A6CBD882432} +MFVideoFormat_DVHD, DV Decoder MFT, {404A6DE5-D4D6-4260-9BC7-5A6CBD882432} +{63616C61-0000-0010-8000-00AA00389B71}, Microsoft ALAC Audio Decoder MFT, {C0CD7D12-31FC-4BBC-B363-7322EE3E1879} +MFVideoFormat_MP4V, Mpeg4s Decoder MFT, CLSID_CMpeg4sDecMFT +MFVideoFormat_MP4S, Mpeg4s Decoder MFT, CLSID_CMpeg4sDecMFT +{53314356-0000-0010-8000-00AA00389B71}, WMVideo Decoder MFT, CLSID_CWMVDecMediaObject +MEDIASUBTYPE_WMVR, WMVideo Decoder MFT, CLSID_CWMVDecMediaObject +MEDIASUBTYPE_WMVP, WMVideo Decoder MFT, CLSID_CWMVDecMediaObject +MFVideoFormat_MJPG, MJPEG Decoder MFT, {CB17E772-E1CC-4633-8450-5617AF577905} +MEDIASUBTYPE_WMVA, WMVideo Decoder MFT, CLSID_CWMVDecMediaObject +{3F40F4F0-5622-4FF8-B6D8-A17A584BEE5E}, Microsoft H264 Video Decoder MFT, CLSID_CMSH264DecoderMFT +MEDIASUBTYPE_mpg4, Mpeg4 Decoder MFT, CLSID_CMpeg4DecMediaObject +MEDIASUBTYPE_MPG4, Mpeg4 Decoder MFT, CLSID_CMpeg4DecMediaObject +MFVideoFormat_H264, Microsoft H264 Video Decoder MFT, CLSID_CMSH264DecoderMFT +MFVideoFormat_WMV3, WMVideo Decoder MFT, CLSID_CWMVDecMediaObject +{33363248-0000-0010-8000-00AA00389B71}, Mpeg4s Decoder MFT, CLSID_CMpeg4sDecMFT +MEDIASUBTYPE_mp43, Mpeg43 Decoder MFT, CLSID_CMpeg43DecMediaObject +MFVideoFormat_MP43, Mpeg43 Decoder MFT, CLSID_CMpeg43DecMediaObject +MEDIASUBTYPE_m4s2, Mpeg4s Decoder MFT, CLSID_CMpeg4sDecMFT +MFVideoFormat_WMV2, WMVideo Decoder MFT, CLSID_CWMVDecMediaObject +MFVideoFormat_MSS2, WMV Screen decoder MFT, CLSID_CMSSCDecMediaObject +MFVideoFormat_M4S2, Mpeg4s Decoder MFT, CLSID_CMpeg4sDecMFT +MEDIASUBTYPE_WVP2, WMVideo Decoder MFT, CLSID_CWMVDecMediaObject +MEDIASUBTYPE_mp42, Mpeg4 Decoder MFT, CLSID_CMpeg4DecMediaObject +MEDIASUBTYPE_MP42, Mpeg4 Decoder MFT, CLSID_CMpeg4DecMediaObject +MFVideoFormat_WMV1, WMVideo Decoder MFT, CLSID_CWMVDecMediaObject +MFVideoFormat_MSS1, WMV Screen decoder MFT, CLSID_CMSSCDecMediaObject +MFVideoFormat_MPG1, Microsoft MPEG Video Decoder MFT, {2D709E52-123F-49B5-9CBC-9AF5CDE28FB9} +MFVideoFormat_WVC1, WMVideo Decoder MFT, CLSID_CWMVDecMediaObject +MFVideoFormat_DVC, DV Decoder MFT, {404A6DE5-D4D6-4260-9BC7-5A6CBD882432} +{0000F1AC-0000-0010-8000-00AA00389B71}, Microsoft FLAC Audio Decoder MFT, {6B0B3E6B-A2C5-4514-8055-AFE8A95242D9} +{00007361-0000-0010-8000-00AA00389B71}, MS AMRNB Decoder MFT, {265011AE-5481-4F77-A295-ABB6FFE8D63E} +{0000704F-0000-0010-8000-00AA00389B71}, Microsoft Opus Audio Decoder MFT, {63E17C10-2D43-4C42-8FE3-8D8B63E46A6A} +{00006C61-0000-0010-8000-00AA00389B71}, Microsoft ALAC Audio Decoder MFT, {C0CD7D12-31FC-4BBC-B363-7322EE3E1879} +{00002001-0000-0010-8000-00AA00389B71}, DTS IEC-61937 converter MFT, {D035E24C-C877-42D7-A795-2A8A339B472F} +{00002000-0000-0010-8000-00AA00389B71}, Microsoft Dolby Digital Plus Decoder MFT, {177C0AFE-900B-48D4-9E4C-57ADD250B3D4} +MFAudioFormat_AAC, Microsoft AAC Audio Decoder MFT, CLSID_CMSAACDecMFT +MFAudioFormat_ADTS, Microsoft AAC Audio Decoder MFT, CLSID_CMSAACDecMFT +MFAudioFormat_WMAudio_Lossless, WMAudio Decoder MFT, CLSID_CWMADecMediaObject +MFAudioFormat_WMAudioV9, WMAudio Decoder MFT, CLSID_CWMADecMediaObject +MFAudioFormat_WMAudioV8, WMAudio Decoder MFT, CLSID_CWMADecMediaObject +MEDIASUBTYPE_MSAUDIO1, WMAudio Decoder MFT, CLSID_CWMADecMediaObject +MEDIASUBTYPE_RAW_AAC1, Microsoft AAC Audio Decoder MFT, CLSID_CMSAACDecMFT +MFAudioFormat_MP3, MP3 Decoder MFT, CLSID_CMP3DecMediaObject +MFAudioFormat_MPEG, Microsoft MPEG Audio Decoder MFT, {70707B39-B2CA-4015-ABEA-F8447D22D88B} +{00000031-0000-0010-8000-00AA00389B71}, GSM ACM Wrapper MFT, {4A76B469-7B66-4DD4-BA2D-DDF244C766DC} +{00000011-0000-0010-8000-00AA00389B71}, IMA ADPCM ACM Wrapper MFT, {A16E1BFF-A80D-48AD-AECD-A35C005685FE} +KSDATAFORMAT_SUBTYPE_MULAW, G711 Wrapper MFT, {92B66080-5E2D-449E-90C4-C41F268E5514} +{00000006-0000-0010-8000-00AA00389B71}, A-law Wrapper MFT, {36CB6E0C-78C1-42B2-9943-846262F31786} +KSDATAFORMAT_SUBTYPE_ADPCM, ADPCM ACM Wrapper MFT, {CA34FE0A-5722-43AD-AF23-05F7650257DD} +WMMEDIASUBTYPE_WMSP2, WMSpeech Decoder DMO, CLSID_CWMSPDecMediaObject +MFAudioFormat_MSP1, WMSpeech Decoder DMO, CLSID_CWMSPDecMediaObject + + +------------------------------------- +Disabled Media Foundation Transforms +------------------------------------- + +[HKEY_LOCAL_MACHINE\Software\Classes\MediaFoundation\Transforms\DoNotUse] + + + + + +------------------------ +Disabled Media Sources +------------------------ + +[HKEY_LOCAL_MACHINE\Software\Classes\MediaFoundation\MediaSources\DoNotUse] + + + + +--------------- +EVR Power Information +--------------- +Current Setting: {5C67A112-A4C9-483F-B4A7-1D473BECAFDC} (Quality) + Quality Flags: 2576 + Enabled: + Force throttling + Allow half deinterlace + Allow scaling + Decode Power Usage: 100 + Balanced Flags: 1424 + Enabled: + Force throttling + Allow batching + Force half deinterlace + Force scaling + Decode Power Usage: 50 + PowerFlags: 1424 + Enabled: + Force throttling + Allow batching + Force half deinterlace + Force scaling + Decode Power Usage: 0 + +--------------- +Diagnostics +--------------- + +Windows Error Reporting: ++++ WER0 +++: +Fault bucket , type 0 +Event Name: MoAppHang +Response: Not available +Cab Id: 0 + +Problem signature: +P1: Microsoft.Windows.Photos_2026.11050.1001.0_x64__8wekyb3d8bbwe +P2: praid:App +P3: 0.0.0.0 +P4: 69f45b56 +P5: 31f2 +P6: 134742016 +P7: +P8: +P9: +P10: + + ++++ WER1 +++: +No Data ++++ WER2 +++: +No Data ++++ WER3 +++: +No Data ++++ WER4 +++: +No Data ++++ WER5 +++: +No Data ++++ WER6 +++: +No Data ++++ WER7 +++: +No Data ++++ WER8 +++: +No Data ++++ WER9 +++: +No Data diff --git a/PC-Multimedia/docs/adr/000-template.md b/PC-Multimedia/docs/adr/000-template.md new file mode 100644 index 0000000..8f802fa --- /dev/null +++ b/PC-Multimedia/docs/adr/000-template.md @@ -0,0 +1,24 @@ +# ADR-000: Template + +> Salin file ini menjadi `ADR-NNNN-judul.md` saat ada keputusan arsitektur baru. + +## Status + +Template + +## Konteks + +{Apa masalah atau kebutuhan yang memicu keputusan?} + +## Keputusan + +{Apa yang diputuskan?} + +## Alternatif yang ditolak + +- {Alternatif 1} — {alasan ditolak} + +## Konsekuensi + +- Positif: ... +- Negatif: ... diff --git a/PC-Multimedia/docs/ai-session-summary.md b/PC-Multimedia/docs/ai-session-summary.md new file mode 100644 index 0000000..2ae9a60 --- /dev/null +++ b/PC-Multimedia/docs/ai-session-summary.md @@ -0,0 +1,75 @@ +# AI Session Summary — PC Multimedia + +```yaml +session: 2026-07-06-ollama-fase3 +project: PC-Multimedia +version: 0.3.0 +status: fase1-selesai +next: UI chat Super Apps PWA + user memory +agent: Cascade +branch: main +``` + +## TL;DR + +- **Fase 1 Ollama ✅** — `qwen2.5-coder:14b` + `nomic-embed-text` running GPU, 11.5 GB VRAM +- Fase 2 (pgvector) + Fase 3 (geonet-console `/api/v1/ai/chat`) selesai — detail di [`Ollama/docs/ai-session-summary.md`](../../Ollama/docs/ai-session-summary.md) +- Node ini (`10.100.1.14`) berjalan stabil sebagai GPU inference endpoint + +## Audit Hardware (2026-07-06) + +| Komponen | Nilai | +|----------|-------| +| CPU | Intel Core Ultra 7 265K, 20 CPU @ ~3.9 GHz | +| RAM | 64 GB | +| GPU | NVIDIA GeForce RTX 5060 Ti (~16 GB GDDR7) | +| MB | Gigabyte Z890 AERO G | +| Storage | ~6 TB NVMe (3× drive 2TB) | + +> ⚠️ Koreksi: CPU bukan i5-4460 — data `wmic` via SSH session mengembalikan nilai kosong. DxDiag adalah sumber akurat. + +## Yang sudah dilakukan + +- Install OpenSSH Server di Windows 10 Pro (hostname MULTIMEDIA) +- Firewall rule `OpenSSH-Server-In-TCP` port 22 +- Public key laptop → `C:\ProgramData\ssh\administrators_authorized_keys` +- Alias `multimedia` di `~/.ssh/config` laptop +- Script setup: `server-audit/scripts/setup-ssh-key-multimedia.ps1` +- Entry di `server-audit/host.md` +- Audit hardware DxDiag → update `docs/system-requirements.md` +- **Fase 1:** Install Ollama v0.31.1 via OllamaSetup.exe +- Set `OLLAMA_MODELS=T:\ollama\models`, `OLLAMA_HOST=0.0.0.0:11434` via `setx /M` +- Autostart via Windows Task Scheduler (SYSTEM account, AtStartup) +- Firewall rule `OllamaVLAN`: port 11434 dari `10.100.1.0/24` only +- Pull `qwen2.5-coder:14b` (9.0 GB) + `nomic-embed-text` (274 MB) → tersimpan di `T:\ollama\models` +- Verified: API `http://10.100.1.14:11434` reachable, GPU 11.5 GB / 16 GB VRAM aktif +- Script: `PC-Multimedia/scripts/install-ollama-task.ps1` + +## Fase 1 — Detail Konfigurasi + +| Item | Nilai | +|------|-------| +| Ollama versi | 0.31.1 | +| Ollama path | `C:\Users\admin\AppData\Local\Programs\Ollama\ollama.exe` | +| Model storage | `T:\ollama\models` (Samsung 9100 PRO, 323 GB free) | +| Listen | `0.0.0.0:11434` | +| Autostart | Task Scheduler → Task `OllamaServe`, SYSTEM, AtStartup | +| Firewall | Rule `OllamaVLAN`, TCP 11434, remoteip `10.100.1.0/24` | +| GPU saat idle | ~2213 MiB VRAM | +| GPU saat loaded 14B | ~11518 MiB VRAM | +| CUDA | 12.9 (bundle dari driver 576.88, tidak perlu install terpisah) | + +## Lanjut dari sini + +1. Tidak ada task Ollama baru untuk node ini — sudah stabil +2. Monitor: pastikan Task `OllamaServe` masih running setelah Windows update/reboot +3. Inventarisasi aplikasi terpasang (ArcGIS Pro, dll.) — lihat [todo.md](./todo.md) +4. Opsional: Zabbix agent untuk `10.100.1.14` +5. Next AI pipeline: lihat [`Ollama/docs/ai-session-summary.md`](../../Ollama/docs/ai-session-summary.md) + +## Jangan + +- Jangan simpan password admin di repo +- Jangan commit `.env` lokal +- Jangan pakai `~/.ssh/authorized_keys` untuk user admin Windows — tidak akan jalan +- Jangan expose port 11434 ke luar VLAN `10.100.1.0/24` diff --git a/PC-Multimedia/docs/changelog.md b/PC-Multimedia/docs/changelog.md new file mode 100644 index 0000000..a8f76b5 --- /dev/null +++ b/PC-Multimedia/docs/changelog.md @@ -0,0 +1,15 @@ +# Changelog — PC Multimedia + +Format berdasarkan [Keep a Changelog](https://keepachangelog.com/). + +## [Unreleased] + +## [0.1.0] - 2026-07-06 + +### Added + +- Struktur dokumentasi standar AI-Agent-Standards +- `AGENTS.md`, `.env.example`, `docs/server.md` (dual NIC, SSH key setup) +- OpenSSH Server dokumentasi + passwordless SSH verified +- Script `server-audit/scripts/setup-ssh-key-multimedia.ps1` +- Alias SSH `multimedia` di laptop dev diff --git a/PC-Multimedia/docs/context-index.md b/PC-Multimedia/docs/context-index.md new file mode 100644 index 0000000..a97a0b6 --- /dev/null +++ b/PC-Multimedia/docs/context-index.md @@ -0,0 +1,107 @@ +# Context Index — PC Multimedia + +> Multi-project: `Workspace-Context.md` → `PC-Multimedia/AGENTS.md` → `docs/ai-session-summary.md` → **STOP**. + +--- + +## Zona A — Always-read pointers + +| Item | Value | +|------|-------| +| Nama | PC Multimedia | +| Path monorepo | `PC-Multimedia/` | +| Cold start | [../AGENTS.md](../AGENTS.md) | +| Sesi terakhir | [ai-session-summary.md](./ai-session-summary.md) | +| Priority aktif | [todo.md](./todo.md) | +| Server / infra | [server.md](./server.md) | +| System requirements | [system-requirements.md](./system-requirements.md) | +| Env template | [../.env.example](../.env.example) | +| Versi | 0.1.0 — [version.md](./version.md) | +| Stack | Windows 10 Pro, OpenSSH Server | +| Tipe | infra (workstation) | +| Last updated | 2026-07-06 | + +**Rolling session memory:** hanya [ai-session-summary.md](./ai-session-summary.md). + +--- + +## Zona B — On-demand map + +### Dokumentasi inti + +| Dokumen | Isi | Kapan baca | +|---------|-----|------------| +| [ai-session-summary.md](./ai-session-summary.md) | Narasi sesi | Setelah AGENTS | +| [todo.md](./todo.md) | Priority aktif | Ambil / ubah task | +| [project-status.md](./project-status.md) | Progress | Status luas | +| [issues.md](./issues.md) | Bug / RCA | Troubleshoot SSH | +| [changelog.md](./changelog.md) | Riwayat perubahan | Audit | +| [version.md](./version.md) | Poin per versi | Deploy doc | +| [server.md](./server.md) | Host, IP, SSH, key | Akses remote | +| [system-requirements.md](./system-requirements.md) | OS, OpenSSH | Setup ulang | +| [guide/migration.md](./guide/migration.md) | Migrasi IP/NIC | Ganti IP workstation | +| [adr/](./adr/) | Keputusan arsitektur | Ubah kebijakan akses | + +### Prosedur step-by-step + +| Guide | Path | Kapan baca | +|-------|------|------------| +| Indeks guide | [guide/README.md](./guide/README.md) | Navigasi runbook | +| Migrasi IP/domain | [guide/migration.md](./guide/migration.md) | Ganti IP atau NIC | + +### Parent / sibling (monorepo) + +| Dokumen | Path | Kapan baca | +|---------|------|------------| +| Workspace index | [Workspace-Context.md](../../Workspace-Context.md) | Navigasi monorepo | +| SSH hosts index | [server-audit/host.md](../../server-audit/host.md) | Alias `ssh multimedia` | +| Setup SSH key script | [server-audit/scripts/setup-ssh-key-multimedia.ps1](../../server-audit/scripts/setup-ssh-key-multimedia.ps1) | Ulang key auth | +| ArcGIS dev server | [ArcGIS Enterprise/docs/server.md](../ArcGIS%20Enterprise/docs/server.md) | GIS dev dari workstation | + +--- + +## Struktur project + +``` +PC-Multimedia/ +├── AGENTS.md +├── .env.example +└── docs/ + ├── server.md + ├── system-requirements.md + ├── guide/ + │ ├── README.md + │ └── migration.md + └── ... +``` + +--- + +## Dependency + +| Project / Service | Relasi | +|-------------------|--------| +| `server-audit/` | Script setup SSH, host index | +| `ArcGIS Enterprise/` | Dev GIS server target dari workstation | +| `server-connection/` | Shared DB `10.100.1.25` | + +--- + +## Environment + +| Env | Host | Catatan | +|-----|------|---------| +| dev | `10.100.1.14` (primary) | SSH alias `multimedia` | +| dev | `192.168.0.18` (secondary) | LAN MikroTik | + +Credential: password admin hanya di PC lokal; SSH key di laptop `~/.ssh/`. + +--- + +## Aturan kritis AI + +- Minimal diff — scope workstation MULTIMEDIA saja +- No commit kecuali user minta +- SSH admin → `administrators_authorized_keys`, bukan user `.ssh/authorized_keys` +- Host/IP berubah → update server.md, .env.example, guide/migration.md +- Pengetahuan penting tidak boleh hanya di chat diff --git a/PC-Multimedia/docs/guide/README.md b/PC-Multimedia/docs/guide/README.md new file mode 100644 index 0000000..b0ca37b --- /dev/null +++ b/PC-Multimedia/docs/guide/README.md @@ -0,0 +1,23 @@ +# Guides — PC Multimedia + +## Indeks + +| Guide | Path | Kapan dipakai | +|-------|------|---------------| +| Migrasi IP / NIC | [migration.md](./migration.md) | Ganti IP, tambah NIC, pindah subnet | +| Setup SSH key | [../../server-audit/scripts/setup-ssh-key-multimedia.ps1](../../server-audit/scripts/setup-ssh-key-multimedia.ps1) | Ulang passwordless SSH | + +## OpenSSH — setup awal (referensi) + +Sudah dilakukan 6 Jul 2026. Ulang jika service corrupt: + +```powershell +# Di MULTIMEDIA (PowerShell Admin) +Get-Service sshd +Set-Service sshd -StartupType Automatic +Start-Service sshd +New-NetFirewallRule -Name 'OpenSSH-Server-In-TCP' -DisplayName 'OpenSSH Server (sshd)' ` + -Enabled True -Direction Inbound -Protocol TCP -Action Allow -LocalPort 22 +``` + +Key auth: jalankan [setup-ssh-key-multimedia.ps1](../../server-audit/scripts/setup-ssh-key-multimedia.ps1). diff --git a/PC-Multimedia/docs/guide/migration.md b/PC-Multimedia/docs/guide/migration.md new file mode 100644 index 0000000..5b985ee --- /dev/null +++ b/PC-Multimedia/docs/guide/migration.md @@ -0,0 +1,80 @@ +# Migration Guide — PC Multimedia + +**Owner:** migrasi IP, NIC, atau kebijakan SSH workstation MULTIMEDIA. +Inventori: [../server.md](../server.md) · Env: [../../.env.example](../../.env.example) + +**Prinsip:** ubah `.env` / ssh config / docs — bukan hardcode IP di skrip. + +--- + +## Inventori saat ini (2026-07-06) + +| Item | Nilai saat ini | File yang harus diupdate jika berubah | +|------|----------------|--------------------------------------| +| Hostname | MULTIMEDIA | docs/server.md | +| IP utama (LAN server) | `10.100.1.14` | `.env.example`, docs/server.md, `~/.ssh/config` HostName | +| IP sekunder (LAN MikroTik) | `192.168.0.18` | `.env.example`, docs/server.md, DHCP MikroTik | +| SSH alias | `multimedia` | `~/.ssh/config`, server-audit/host.md | +| SSH user | `admin` | docs/server.md | +| SSH port | `22` | — | +| Gateway utama | `10.100.1.1` | `.env.example` | +| Gateway sekunder | `192.168.0.1` | `.env.example` | + +--- + +## Variabel env yang terpengaruh + +| Variabel | Saat ini | New (isi saat migrasi) | +|----------|----------|------------------------| +| `HOST_IP_PRIMARY` | `10.100.1.14` | | +| `HOST_IP_SECONDARY` | `192.168.0.18` | | +| `GATEWAY_PRIMARY` | `10.100.1.1` | | +| `GATEWAY_SECONDARY` | `192.168.0.1` | | + +--- + +## Langkah migrasi IP (workstation) + +1. **Persiapan** + - [ ] Catat IP/MAC/gateway lama di [../server.md](../server.md) + - [ ] Pastikan akses fisik/RDP ke PC jika SSH putus + +2. **Ubah IP di Windows** + - [ ] Network adapter → TCP/IPv4 → IP baru + - [ ] Tes ping gateway & server infra + +3. **SSH & firewall** + - [ ] `Get-Service sshd` — masih Running + - [ ] Firewall rule port 22 masih aktif + - [ ] Host key tetap sama (kecuali reinstall OpenSSH) + +4. **Update laptop dev** + - [ ] `~/.ssh/config` — ubah `HostName` pada `Host multimedia` + - [ ] `known_hosts` — tambah IP baru atau hapus entry lama + - [ ] Tes: `ssh multimedia hostname` + +5. **Update repo** + - [ ] [../server.md](../server.md) + - [ ] [../../.env.example](../../.env.example) + - [ ] [../../server-audit/host.md](../../server-audit/host.md) + - [ ] [../../Workspace-Context.md](../../Workspace-Context.md) Server Index + - [ ] Append [../version.md](../version.md) + [../changelog.md](../changelog.md) + +6. **MikroTik (jika IP sekunder berubah)** + - [ ] Update DHCP reservation MAC `10:ff:e0:3a:7d:15` + +--- + +## Rollback + +1. Kembalikan IP di Windows ke nilai lama +2. Restore `~/.ssh/config` laptop +3. Catat di [../issues.md](../issues.md) + +--- + +## Riwayat migrasi + +| Tanggal | Dari | Ke | Catatan | +|---------|------|-----|---------| +| 2026-07-06 | — | Bootstrap docs | OpenSSH + dual NIC didokumentasikan | diff --git a/PC-Multimedia/docs/issues.md b/PC-Multimedia/docs/issues.md new file mode 100644 index 0000000..b7ab3c3 --- /dev/null +++ b/PC-Multimedia/docs/issues.md @@ -0,0 +1,19 @@ +# Issues — PC Multimedia + +## Open + +_(belum ada issue terdaftar)_ + +## Fixed + +### SSH masih minta password meskipun key sudah di-copy ke `~/.ssh/authorized_keys` + +- **Gejala:** `ssh admin@192.168.0.18` selalu prompt password +- **Penyebab:** User `admin` termasuk grup Administrators — Windows OpenSSH hanya membaca `C:\ProgramData\ssh\administrators_authorized_keys`, **bukan** `C:\Users\admin\.ssh\authorized_keys` +- **Fix:** Tambah public key ke `administrators_authorized_keys` + ACL `SYSTEM:(F)` / `Administrators:(F)` + `Restart-Service sshd` +- **Script:** `server-audit/scripts/setup-ssh-key-multimedia.ps1` +- **Status:** Fixed 2026-07-06 + +## Known / Watch + +- Dual NIC — pastikan SSH dari subnet yang benar (`10.100.1.14` dari LAN server, `192.168.0.18` dari LAN MikroTik) diff --git a/PC-Multimedia/docs/project-status.md b/PC-Multimedia/docs/project-status.md new file mode 100644 index 0000000..b7d5a2d --- /dev/null +++ b/PC-Multimedia/docs/project-status.md @@ -0,0 +1,32 @@ +# Project Status — PC Multimedia + +**Last updated:** 2026-07-06 + +## Ringkasan + +Workstation Windows 10 Pro **MULTIMEDIA** — akses remote via OpenSSH untuk dev/GIS dari laptop infrastruktur. + +## Progress + +| Area | Status | +|------|--------| +| Dokumentasi | Done (bootstrap 0.1.0) | +| OpenSSH Server | Done — Running, Automatic | +| Passwordless SSH | Done — verified | +| Inventarisasi aplikasi | Not started | +| Monitoring (Zabbix) | Not started | + +## Next priority + +Lihat [todo.md](./todo.md) — inventarisasi aplikasi terpasang. + +## Server + +| Item | Nilai | +|------|-------| +| Hostname | MULTIMEDIA | +| IP utama | `10.100.1.14` | +| IP sekunder | `192.168.0.18` | +| SSH | `ssh multimedia` | + +Detail: [server.md](./server.md) diff --git a/PC-Multimedia/docs/server.md b/PC-Multimedia/docs/server.md new file mode 100644 index 0000000..4ef65dd --- /dev/null +++ b/PC-Multimedia/docs/server.md @@ -0,0 +1,124 @@ +# Server Inventory — PC Multimedia + +**Owner:** host/IP, SSH, runtime workstation MULTIMEDIA. +Indeks lintas project: [Workspace-Context.md](../../Workspace-Context.md) · SSH cepat: [server-audit/host.md](../../server-audit/host.md) + +--- + +## Ringkasan + +| Field | Value | +|-------|-------| +| Project | `PC-Multimedia/` | +| Last updated | 2026-07-06 | +| Credential location | Password admin di PC lokal saja; SSH key di laptop `~/.ssh/id_ed25519_geonet_proxmox` | + +--- + +## Host / Server + +| Host / IP | Env | Role | OS | Akses | Catatan | +|-----------|-----|------|-----|-------|---------| +| `MULTIMEDIA` / `10.100.1.14` | dev | Workstation (utama) | Windows 10 Pro | `ssh multimedia` | NIC Ethernet — LAN server `10.100.1.0/24`, GW `10.100.1.1` | +| `192.168.0.18` | dev | Workstation (sekunder) | Windows 10 Pro | `ssh admin@192.168.0.18` | NIC Ethernet 2 — LAN MikroTik `192.168.0.0/24`, GW `192.168.0.1` | + +**DHCP MikroTik:** `192.168.0.18` — MAC `10:ff:e0:3a:7d:15` (lihat `server-connection/config-check.rsc`) + +--- + +## Aplikasi & Runtime per Host + +| Host / IP | Aplikasi | Jenis | Port | Path / Service | Catatan | +|-----------|----------|-------|------|----------------|---------| +| 10.100.1.14 | OpenSSH SSH Server | Windows Service | 22 | `sshd` (Automatic) | Passwordless via `administrators_authorized_keys` | +| 10.100.1.14 | Windows Firewall | Rule | 22 | `OpenSSH-Server-In-TCP` | Inbound Allow TCP 22 | + +Wi-Fi: disconnected (audit 6 Jul 2026) + +--- + +## SSH — Konfigurasi + +### Dari laptop dev + +```text +ssh multimedia # → 10.100.1.14, user admin, key otomatis +ssh admin@10.100.1.14 # sama, explicit IP +ssh admin@192.168.0.18 # via LAN MikroTik +``` + +### `~/.ssh/config` (laptop) + +```text +Host multimedia 10.100.1.14 192.168.0.18 + HostName 10.100.1.14 + User admin + Port 22 + IdentityFile ~/.ssh/id_ed25519_geonet_proxmox + IdentitiesOnly yes +``` + +### Di PC MULTIMEDIA (key auth untuk admin) + +| Item | Path / nilai | +|------|----------------| +| Public key file | `C:\ProgramData\ssh\administrators_authorized_keys` | +| Key | `ssh-ed25519 ... proxmox-geonet` (dari `id_ed25519_geonet_proxmox.pub` laptop) | +| ACL | `SYSTEM:(F)`, `Administrators:(F)`, inheritance disabled | +| Setup ulang | [server-audit/scripts/setup-ssh-key-multimedia.ps1](../../server-audit/scripts/setup-ssh-key-multimedia.ps1) | + +> **Penting:** Untuk user di grup Administrators, Windows OpenSSH **mengabaikan** `C:\Users\admin\.ssh\authorized_keys`. + +### Host key (ED25519) + +Fingerprint: `SHA256:VxUdCFwVQ9lIoX1km6H243NPI1lSo6My1B5YnGX8iX0` + +--- + +## Database + +Tidak ada database lokal di workstation ini. Koneksi DB remote (jika dipakai untuk dev GIS): + +| Host | Engine | Dipakai untuk | Credential | +|------|--------|---------------|------------| +| `10.100.1.25` | SQL Server + PostgreSQL | Dev DB shared | [ArcGIS Enterprise/.env](../ArcGIS%20Enterprise/.env) (lokal laptop, jangan commit) | + +--- + +## Endpoint & URL + +| Env | URL / Host:Port | Env var | Catatan | +|-----|-----------------|---------|---------| +| dev | `admin@10.100.1.14:22` | `HOST_IP_PRIMARY`, `SSH_ALIAS` | Akses utama dari LAN server | +| dev | `admin@192.168.0.18:22` | `HOST_IP_SECONDARY` | Akses dari LAN MikroTik | + +--- + +## Mapping ke path project (monorepo) + +| Komponen | Path di monorepo | Keterangan | +|----------|------------------|------------| +| Dokumentasi workstation | `PC-Multimedia/` | SSOT project ini | +| Script setup SSH key | `server-audit/scripts/setup-ssh-key-multimedia.ps1` | Jalankan sekali di PC (Admin) | +| SSH index lintas host | `server-audit/host.md` | Entry cepat `ssh multimedia` | + +--- + +## Dependency server ke project lain + +| Host / Service | Project monorepo | Relasi | +|----------------|------------------|--------| +| `10.100.1.51` (DEV11) | ArcGIS Enterprise | Dev GIS server — akses dari workstation | +| `10.100.1.25` | server-connection, GeoNetAgent | Shared DB | +| `10.100.1.1` / `192.168.0.1` | server-audit | MikroTik gateway | + +--- + +## Catatan operasional + +- **Dual NIC:** gunakan `10.100.1.14` saat laptop di subnet `10.100.1.x` (sama dengan server infra) +- **Port 22:** terbuka di kedua IP (terverifikasi 6 Jul 2026) +- **Passwordless SSH:** terverifikasi `ssh multimedia hostname` → `MULTIMEDIA`, `whoami` → `multimedia\admin` +- OpenSSH diinstall manual Jul 2026; service `sshd` Running, StartupType Automatic + +**Jangan:** simpan password admin atau private key di repo. diff --git a/PC-Multimedia/docs/system-requirements.md b/PC-Multimedia/docs/system-requirements.md new file mode 100644 index 0000000..279fe65 --- /dev/null +++ b/PC-Multimedia/docs/system-requirements.md @@ -0,0 +1,99 @@ +# System Requirements — PC Multimedia + +**Owner:** spesifikasi minimum workstation MULTIMEDIA. +Inventori host: [server.md](./server.md) + +--- + +## Ringkasan + +| Field | Value | +|-------|-------| +| Project | `PC-Multimedia/` | +| Tipe | infra (workstation) | +| Last updated | 2026-07-06 | +| Sumber data | DxDiag.txt — audit 2026-07-06 | + +--- + +## Hardware (Aktual — DxDiag 2026-07-06) + +| Komponen | Nilai | +|----------|-------| +| Motherboard | Gigabyte Z890 AERO G | +| BIOS | F9 (UEFI) | +| CPU | Intel Core Ultra 7 265K — 20 CPU @ ~3.9 GHz | +| RAM | 64 GB (65536 MB total, 65238 MB available OS memory) | +| GPU | NVIDIA GeForce RTX 5060 Ti | +| DirectX | DirectX 12 | +| Display | 1920 × 1080 @ 32Hz | +| Storage | XPG GAMMIX S70 BLADE 2TB + ADATA LEGEND 860 2TB + Samsung SSD 9100 PRO 2TB | + +> **Catatan GPU:** `Display Memory` dilaporkan "Unknown" untuk RTX 5060 Ti via Remote Display Adapter session; nilai VRAM aktual ~16 GB (tipe GDDR7). Dedicated Memory `n/a` karena sesi SSH/RDP — jalankan DxDiag langsung di console untuk nilai akurat. + +--- + +## Platform & OS + +| Komponen | Minimum | Dipakai saat ini | Catatan | +|----------|---------|------------------|---------| +| OS | Windows 10 Pro | Windows 10 Pro | Hostname: MULTIMEDIA | +| Arsitektur | x64 | x64 | | +| RAM | 16 GB | **64 GB** | Intel Core Ultra 7 265K build | +| GPU | — | **NVIDIA GeForce RTX 5060 Ti** | CUDA-capable; cocok untuk GPU inference Ollama | + +--- + +## Runtime & Toolchain + +| Tool | Versi minimum | Dipakai saat ini | Install / cek | +|------|---------------|------------------|---------------| +| OpenSSH Server | Windows 10 built-in / optional feature | OpenSSH_for_Windows_10.0 | `Get-Service sshd` | +| PowerShell | 5.1+ | 5.1 | Default Windows 10 | +| CUDA Toolkit | 12.x | ✅ 12.9 (bundle driver 576.88) | Tidak perlu install terpisah | +| Ollama | Latest | ✅ v0.31.1 | `C:\Users\admin\AppData\Local\Programs\Ollama\ollama.exe` | +| Ollama autostart | Task Scheduler | ✅ Task `OllamaServe` (SYSTEM, AtStartup) | `scp` + `install-ollama-task.ps1` | + +--- + +## Dependency eksternal (opsional dev) + +| Dependency | Host | Dipakai untuk | Owner docs | +|------------|------|---------------|------------| +| ArcGIS Enterprise | `10.100.1.51` | GIS dev | [ArcGIS Enterprise/docs/server.md](../ArcGIS%20Enterprise/docs/server.md) | +| PostgreSQL / SQL Server | `10.100.1.25` | Shared DB dev | [server-connection/docs/server.md](../server-connection/docs/server.md) | + +--- + +## Variabel URL & konfigurasi + +Semua host/IP **wajib** dari env — lihat [.env.example](../.env.example): + +| Variabel | Fungsi | +|----------|--------| +| `HOST_IP_PRIMARY` | IP utama LAN server (`10.100.1.14`) | +| `HOST_IP_SECONDARY` | IP LAN MikroTik (`192.168.0.18`) | +| `SSH_ALIAS` | Alias SSH (`multimedia`) | +| `SSH_USER` | User Windows (`admin`) | +| `SSH_PORT` | Port SSH (`22`) | + +**Aturan:** no hardcode IP di skrip repo — pakai env atau ssh alias. + +--- + +## Network requirements + +| Interface | IP | Subnet | Gateway | Kapan dipakai | +|-----------|-----|--------|---------|---------------| +| Ethernet | `10.100.1.14` | `255.255.255.0` | `10.100.1.1` | Akses ke server infra `10.100.1.x` | +| Ethernet 2 | `192.168.0.18` | `255.255.255.0` | `192.168.0.1` | Akses dari jaringan MikroTik | + +--- + +## Laptop dev (klien SSH) + +| Tool | Catatan | +|------|---------| +| OpenSSH Client | Windows 10+ / PowerShell | +| SSH key | `~/.ssh/id_ed25519_geonet_proxmox` | +| Config alias | `Host multimedia` di `~/.ssh/config` | diff --git a/PC-Multimedia/docs/todo.md b/PC-Multimedia/docs/todo.md new file mode 100644 index 0000000..67d831c --- /dev/null +++ b/PC-Multimedia/docs/todo.md @@ -0,0 +1,28 @@ +# Todo — PC Multimedia + +## High + +- [ ] Fase 2: pgvector extension + DB `geonet_project_search` di PostgreSQL `10.100.1.25` +- [ ] Fase 2: Script indexer — crawl monorepo `d:\Project\app on git` → chunk → embed → pgvector +- [ ] Fase 3: Endpoint `POST /api/v1/ai/chat` di geonet-console dengan system prompt + user memory + +> Detail teknis: lihat [Ollama/docs/todo.md](../../Ollama/docs/todo.md) + +## Medium + +- [ ] Inventarisasi aplikasi GIS/dev terpasang di MULTIMEDIA (ArcGIS Pro, browser, tools) + +## Low + +- [ ] Pertimbangkan monitoring Zabbix untuk host `10.100.1.14` + +## Selesai (Sesi Ini) + +- [x] Bootstrap dokumentasi standar AI-Agent-Standards +- [x] Install & konfigurasi OpenSSH Server +- [x] Setup passwordless SSH (key `id_ed25519_geonet_proxmox`) +- [x] Dokumentasi dual NIC + alias `multimedia` +- [x] Script setup key: `server-audit/scripts/setup-ssh-key-multimedia.ps1` +- [x] Audit hardware via DxDiag: Core Ultra 7 265K, 64 GB RAM, RTX 5060 Ti +- [x] **Fase 1 Ollama GPU** — Ollama v0.31.1, `qwen2.5-coder:14b` + `nomic-embed-text`, GPU inference verified +- [x] Task Scheduler autostart `OllamaServe` (SYSTEM) + Firewall rule VLAN port 11434 diff --git a/PC-Multimedia/docs/version.md b/PC-Multimedia/docs/version.md new file mode 100644 index 0000000..ad28de8 --- /dev/null +++ b/PC-Multimedia/docs/version.md @@ -0,0 +1,22 @@ +# Version History — PC Multimedia + +## [0.2.0] - 2026-07-06 + +- **Fase 1 Ollama GPU selesai** — install Ollama v0.31.1, GPU inference aktif +- Model: `qwen2.5-coder:14b` (9 GB) + `nomic-embed-text` (274 MB) di `T:\ollama\models` +- Autostart via Task Scheduler SYSTEM + Firewall rule VLAN-only port 11434 +- Verified: API `http://10.100.1.14:11434` reachable, VRAM 11.5 GB / 16 GB saat loaded +- Script: `scripts/install-ollama-task.ps1` + +## [0.1.1] - 2026-07-06 + +- Audit hardware aktual via DxDiag + `wmic` SSH +- Update `docs/system-requirements.md`: CPU Intel Core Ultra 7 265K, RAM 64 GB, GPU RTX 5060 Ti, MB Gigabyte Z890 AERO G +- Tambah toolchain CUDA Toolkit + Ollama (belum install) ke runtime table + +## [0.1.0] - 2026-07-06 + +- Bootstrap dokumentasi standar (AGENTS.md + docs/) +- Inisialisasi project PC Multimedia (workstation MULTIMEDIA) +- Dokumentasi OpenSSH + dual NIC (`10.100.1.14`, `192.168.0.18`) +- Passwordless SSH verified dari laptop dev diff --git a/PC-Multimedia/scripts/install-ollama-task.ps1 b/PC-Multimedia/scripts/install-ollama-task.ps1 new file mode 100644 index 0000000..0100d27 --- /dev/null +++ b/PC-Multimedia/scripts/install-ollama-task.ps1 @@ -0,0 +1,18 @@ +# Install Ollama sebagai Scheduled Task (run at startup, SYSTEM account) +# Jalankan sebagai Administrator + +$ollamaExe = "C:\Users\admin\AppData\Local\Programs\Ollama\ollama.exe" + +$action = New-ScheduledTaskAction -Execute $ollamaExe -Argument "serve" +$trigger = New-ScheduledTaskTrigger -AtStartup +$settings = New-ScheduledTaskSettingsSet -ExecutionTimeLimit 0 -RestartCount 3 -RestartInterval (New-TimeSpan -Minutes 1) +$principal = New-ScheduledTaskPrincipal -UserId "SYSTEM" -LogonType ServiceAccount -RunLevel Highest + +Register-ScheduledTask -TaskName "OllamaServe" -Action $action -Trigger $trigger -Settings $settings -Principal $principal -Force + +Write-Host "Registered. Starting now..." +Start-ScheduledTask -TaskName "OllamaServe" + +Start-Sleep -Seconds 3 +$state = (Get-ScheduledTask -TaskName "OllamaServe").State +Write-Host "Task state: $state" diff --git a/Workspace-Context.md b/Workspace-Context.md index 692b6ff..2fcd204 100644 --- a/Workspace-Context.md +++ b/Workspace-Context.md @@ -28,18 +28,67 @@ Selalu identifikasi repository yang relevan, kemudian baca **`docs/context-index Workspace ini berisi beberapa repository. **Jangan analisis semuanya sekaligus** — pilih yang relevan. -| Repository | Path lokal | Git remote | Entry point | Peran | -|------------|------------|------------|-------------|-------| -| **LDAPWeb (monorepo)** | `D:\Project\app on git\` | `git.gisportal.id/rbsetiawan/LDAPWeb` | `Workspace-Context.md` | Root workspace, dokumentasi lintas-repo | -| **GeoNetAgent** | `GeoNetAgent/` | (dalam monorepo LDAPWeb) | `GeoNetAgent/docs/context-index.md` | Agent Windows, collector FastAPI, infra asset | -| **server-connection** | `server-connection/` | (dalam monorepo LDAPWeb) | `server-connection/docs/context-index.md` | Backend Laravel: geonet-console, databaselist, sqlservercheck | -| **mysupperapps_FE_PWA** | `mysupperapps_FE_PWA/` | `git.gisportal.id/rbsetiawan/mysupperapps-fe-pwa` | `mysupperapps_FE_PWA/docs/context-index.md` | Frontend PWA Next.js — `https://my.gisportal.id` | +| Repository | Path lokal | Git remote | Cold start | Peran | +|------------|------------|------------|------------|-------| +| **LDAPWeb (monorepo)** | `D:\Project\app on git\` | `git.gisportal.id/rbsetiawan/LDAPWeb` | `Workspace-Context.md` | Root workspace, navigasi lintas-repo | +| **Mailcow** | `Mailcow/` | (monorepo) | [`Mailcow/AGENTS.md`](Mailcow/AGENTS.md) | Mail server `sync.geonet.co.id` | +| **Ollama** | `Ollama/` | (monorepo) | [`Ollama/AGENTS.md`](Ollama/AGENTS.md) | AI inference on-prem `10.100.1.26` | +| **Mikrotik** | `Mikrotik/` | (monorepo) | [`Mikrotik/AGENTS.md`](Mikrotik/AGENTS.md) | Gateway NAT/firewall `10.100.1.1` | +| **GeoNetAgent** | `GeoNetAgent/` | (monorepo) | [`GeoNetAgent/AGENTS.md`](GeoNetAgent/AGENTS.md) | Agent Windows + collector FastAPI | +| **server-connection** | `server-connection/` | (monorepo) | [`server-connection/AGENTS.md`](server-connection/AGENTS.md) | geonet-console, databaselist, sqlservercheck | +| **Zammad** | `Zammad/` | (monorepo) | [`Zammad/AGENTS.md`](Zammad/AGENTS.md) | Helpdesk `zammad.gisportal.id` | +| **nginx** | `nginx/` | (monorepo) | [`nginx/AGENTS.md`](nginx/AGENTS.md) | Reverse proxy `10.100.1.24` | +| **Dockge** | `Dockge/` | (monorepo) | [`Dockge/AGENTS.md`](Dockge/AGENTS.md) | Docker stack manager | +| **ArcGIS Enterprise** | `ArcGIS Enterprise/` | (monorepo) | [`ArcGIS Enterprise/AGENTS.md`](ArcGIS%20Enterprise/AGENTS.md) | ESRI dev stack `.51`–`.53` | +| **PC-Multimedia** | `PC-Multimedia/` | (monorepo) | [`PC-Multimedia/AGENTS.md`](PC-Multimedia/AGENTS.md) | Workstation MULTIMEDIA `10.100.1.14` | +| **mysupperapps_FE_PWA** | `mysupperapps_FE_PWA/` *(gitignored)* | `git.gisportal.id/rbsetiawan/mysupperapps-fe-pwa` | [`mysupperapps_FE_PWA/AGENTS.md`](mysupperapps_FE_PWA/AGENTS.md) | FE PWA `my.gisportal.id` | +| **AI-Agent-Standards** | `AI-Agent-Standards/` | (monorepo) | [`AI-Agent-Standards/README.md`](AI-Agent-Standards/README.md) | **SSOT** template docs & handover | **Catatan `mysupperapps_FE_PWA`:** -- Repo Git **terpisah** (microservice + FE UI) — sengaja dipisah dari monorepo LDAPWeb. -- Folder lokal di-ignore di `.gitignore` root monorepo; commit & push hanya dari repo FE sendiri. +- Repo Git **terpisah** — folder lokal di-ignore di monorepo. +- Cold start: [`mysupperapps_FE_PWA/AGENTS.md`](mysupperapps_FE_PWA/AGENTS.md) → `docs/ai-session-summary.md` - Backend API: `server-connection/geonet-console` (`console.gisportal.id/api/v1`). -- Pekerjaan full-stack: baca `docs/context-index.md` **kedua** repo (FE + backend). + +--- + +# Documentation Standard (SSOT) + +Standar wajib: [`AI-Agent-Standards/prompts/bootstrap-new-project.md`](AI-Agent-Standards/prompts/bootstrap-new-project.md) + +Setiap repo wajib punya (minimum): + +``` +{repo}/AGENTS.md +{repo}/.env.example +{repo}/docs/version.md ← append setiap deploy/perbaikan material +{repo}/docs/ai-session-summary.md +{repo}/docs/context-index.md +{repo}/docs/guide/migration.md +{repo}/docs/system-requirements.md +{repo}/docs/server.md +``` + +**Version policy:** setiap deploy, cutover, atau perbaikan material → **append** bullet poin di `docs/version.md` (jangan overwrite). Sinkron dengan `changelog.md`. + +Cold start agent: `AGENTS.md` → `docs/ai-session-summary.md` → STOP (~2000 token). + +Akhir sesi: [`AI-Agent-Standards/prompts/end-of-session-handover.md`](AI-Agent-Standards/prompts/end-of-session-handover.md) + +--- + +## Server Index (lintas project) + +| Host / IP | Project | Role | Detail | +|-----------|---------|------|--------| +| `10.100.1.1` | Mikrotik | Gateway, NAT, dual-WAN | [Mikrotik/docs/server.md](Mikrotik/docs/server.md) | +| `10.100.1.24` | nginx, Dockge, server-connection, Zammad, GeoNetAgent | Reverse proxy, Docker stacks | [nginx/docs/server.md](nginx/docs/server.md) | +| `10.100.1.25` | server-connection, GeoNetAgent | PostgreSQL | [server-connection/docs/server.md](server-connection/docs/server.md) | +| `10.100.1.26` | Ollama, server-connection | AI inference (Ollama CPU) | [Ollama/docs/server.md](Ollama/docs/server.md) | +| `10.100.1.28` | Mailcow, Dockge agent | Mailcow VM | [Mailcow/docs/server.md](Mailcow/docs/server.md) | +| `10.100.1.40` | server-connection, Zammad, Mailcow | Active Directory LDAP | [server-connection/docs/environment.md](server-connection/docs/environment.md) | +| `10.100.1.51`–`.53` | ArcGIS Enterprise | ESRI dev | [ArcGIS Enterprise/docs/server.md](ArcGIS%20Enterprise/docs/server.md) | +| `10.100.1.14` | PC-Multimedia | Workstation dev/GIS | [PC-Multimedia/docs/server.md](PC-Multimedia/docs/server.md) | +| `117.102.73.102` | Mailcow, nginx | IP publik NAT | [Mailcow/docs/server.md](Mailcow/docs/server.md) | --- @@ -106,6 +155,7 @@ Minimal dokumentasi yang harus diperbarui apabila relevan: * Next Action * ADR (Architecture Decision Record) * Changelog +* **Version history** (`docs/version.md` — append per deploy) * API Documentation * Database Structure * Database Migration @@ -185,6 +235,7 @@ Sebuah pekerjaan **belum dianggap selesai** apabila salah satu kondisi berikut m * API belum diperbarui. * ADR belum dibuat (jika diperlukan). * Changelog belum diperbarui. +* `docs/version.md` belum di-append untuk deploy/perbaikan material. * `docs/context-index.md` belum diperbarui apabila terdapat dokumen baru. --- diff --git a/Workspace-Session.md b/Workspace-Session.md index 03af250..552d989 100644 Binary files a/Workspace-Session.md and b/Workspace-Session.md differ diff --git a/Zammad/.cursor/rules/project-context.mdc b/Zammad/.cursor/rules/project-context.mdc new file mode 100644 index 0000000..dc287e3 --- /dev/null +++ b/Zammad/.cursor/rules/project-context.mdc @@ -0,0 +1,35 @@ +--- +description: Konteks proyek Zammad — ticketing Super Apps, OSS, LDAP +alwaysApply: true +--- + +# Zammad — Project Context + +**Status: Fase 0 selesai** → Fase 1 install berikutnya. Progress: `docs/project-status.md` + +Sebelum asumsi tentang stack atau deploy, baca urutan ini: + +1. `docs/context-index.md` — **entry point** & peta dokumen +2. `docs/project-status.md` — fase & milestone +3. `docs/todo.md` — next actions +4. Task-specific: + - Deploy → `docs/deployment.md` + - OSS/S3 → `docs/storage.md` + - Env → `docs/environment.md` + - Server/SSH → `docs/server.md` + - API FE → `docs/api/overview.md` + - ADR → `docs/adr/` +5. Lintas repo (jangan duplikasi): + - LDAP/OSS umum → `server-connection/docs/context-index.md` + - FE `/ticketing` → `mysupperapps_FE_PWA/docs/context-index.md` + +## Ringkasan Cepat + +- **Platform:** Zammad (Docker) di `10.100.1.24` +- **URL target:** `https://zammad.gisportal.id` +- **DB:** PostgreSQL eksternal `10.100.1.25` — database `zammad` +- **Attachments:** QNAP OSS bucket `zammad-attachments` (private) +- **Auth:** LDAP AD `10.100.1.40` +- **Jangan** commit secret; `.env` hanya di server `/opt/stacks/zammad/` +- **SSH** ke server wajib minta persetujuan user +- **Sync:** ikuti `perintah.md` sebelum nyatakan selesai diff --git a/Zammad/.env.example b/Zammad/.env.example new file mode 100644 index 0000000..a3044e3 --- /dev/null +++ b/Zammad/.env.example @@ -0,0 +1,31 @@ +# .env.example — Zammad (referensi deploy) +# Nilai aktual di /opt/stacks/zammad/.env (server) — JANGAN commit + +ZAMMAD_FQDN=zammad.gisportal.id +ZAMMAD_STACK_PATH=/opt/stacks/zammad +ZAMMAD_HTTP_PORT=8093 + +# LDAP +LDAP_HOST=10.100.1.40 +LDAP_PORT=389 +LDAP_BASE_DN=DC=gisportal,DC=id + +# OSS attachments (QNAP) +OSS_ENDPOINT=https://file.gisportal.id +OSS_BUCKET=zammad-attachments +OSS_ACCESS_KEY= +OSS_SECRET_KEY= + +# SMTP (transisi — ganti ke Mailcow Fase 3) +SMTP_HOST=sc138.idcloudhosting.cloud +SMTP_PORT=465 +SMTP_USER=support@geonet.co.id +SMTP_PASSWORD= + +# Mailcow target (Fase 3) +MAILCOW_IMAP_HOST=sync.geonet.co.id +MAILCOW_IMAP_PORT=993 +MAILCOW_SMTP_HOST=sync.geonet.co.id +MAILCOW_SMTP_PORT=587 + +# Docs: docs/system-requirements.md diff --git a/Zammad/.gitignore b/Zammad/.gitignore new file mode 100644 index 0000000..d91208b --- /dev/null +++ b/Zammad/.gitignore @@ -0,0 +1,14 @@ +# Environment & secrets — never commit +.env +.env.* +!.env.example + +# Zammad docker-compose local overrides +infra/zammad/.env + +# OS / editor +.DS_Store +Thumbs.db +*.swp +.idea/ +.vscode/ diff --git a/Zammad/AGENTS.md b/Zammad/AGENTS.md new file mode 100644 index 0000000..45838a2 --- /dev/null +++ b/Zammad/AGENTS.md @@ -0,0 +1,34 @@ +# AGENTS.md — Cold Start + +> Project: `Zammad/` +> Sesi: [docs/ai-session-summary.md](./docs/ai-session-summary.md) +> Peta: [docs/context-index.md](./docs/context-index.md) +> Env: [.env.example](./.env.example) + +## Apa ini? + +Helpdesk/ticketing Zammad untuk Super Apps — `zammad.gisportal.id`; integrasi FE `/ticketing`, LDAP AD, OSS attachments. + +## Aturan kritis + +- **No hardcoded URL/IP** — `.env` / `infra/` templates +- No commit secret; token di `/opt/stacks/zammad/.fe-ticketing-token` (server) +- No commit kecuali user minta +- **Deploy:** append [docs/version.md](./docs/version.md) +- Stack path: `/opt/stacks/zammad` di `10.100.1.24` +- Pengetahuan penting **wajib ke docs** + +## Lanjut kerja + +``` +1. AGENTS.md → docs/ai-session-summary.md → STOP +2. docs/todo.md, docs/deployment.md, docs/server.md +``` + +## Pointer + +| Butuh | Buka | +|-------|------| +| Versi | [docs/version.md](./docs/version.md) | +| Mailcow channel | `Mailcow/docs/notes/zammad-email-channel.md` | +| FE integrasi | [docs/notes/fe-ticketing-integration.md](./docs/notes/fe-ticketing-integration.md) | diff --git a/Zammad/README.md b/Zammad/README.md new file mode 100644 index 0000000..1fa0a46 --- /dev/null +++ b/Zammad/README.md @@ -0,0 +1,15 @@ +# Zammad — IT Helpdesk (Super Apps) + +Microservice ticketing untuk **Super Apps** (`my.gisportal.id`). + +| Item | Nilai | +|------|-------| +| Platform | [Zammad](https://zammad.org/) (Docker) | +| Domain (target) | `https://zammad.gisportal.id` | +| Server | `10.100.1.24` (Docker stack) | +| Database | PostgreSQL `10.100.1.25` (eksternal) | +| Auth | LDAP Active Directory `10.100.1.40` | +| Attachment storage | QNAP OSS bucket `zammad-attachments` | +| FE integration | `mysupperapps_FE_PWA` → `/ticketing` | + +**AI entry point:** [`docs/context-index.md`](docs/context-index.md) diff --git a/Zammad/docs/adr/ADR-0001-zammad-ticketing-platform.md b/Zammad/docs/adr/ADR-0001-zammad-ticketing-platform.md new file mode 100644 index 0000000..3a70cb6 --- /dev/null +++ b/Zammad/docs/adr/ADR-0001-zammad-ticketing-platform.md @@ -0,0 +1,49 @@ +# ADR-0001: Zammad sebagai Platform Ticketing + +**Status:** Accepted +**Date:** 2026-07-02 + +--- + +## Context + +Super Apps membutuhkan modul ticketing untuk support internal. Opsi yang dipertimbangkan: + +- Jira di VM `10.100.1.55` (disabled oleh user) +- Zammad (open source, Docker, LDAP, REST API) +- Mailcow-first tanpa helpdesk + +--- + +## Decision + +Gunakan **Zammad** di `10.100.1.24`, domain **`zammad.gisportal.id`**, dengan: + +- PostgreSQL eksternal di `10.100.1.25` +- Elasticsearch enabled +- LDAP ke AD `10.100.1.40` +- Integrasi FE via REST API di `mysupperapps_FE_PWA` + +--- + +## Consequences + +**Positive** + +- REST API siap untuk FE `/ticketing` +- LDAP konsisten dengan geonet-console +- OSS attachment terpisah dari avatar publik + +**Negative** + +- Stack tambahan (ES + Redis) di server .24 +- Mail channel menunggu Mailcow (fase berikutnya) + +--- + +## Alternatives rejected + +| Alternatif | Alasan ditolak | +|------------|----------------| +| Jira VM .55 | VM disabled | +| Ticketing custom di Laravel | Duplikasi effort; Zammad mature untuk workflow tiket | diff --git a/Zammad/docs/adr/ADR-0002-oss-attachments-qnap.md b/Zammad/docs/adr/ADR-0002-oss-attachments-qnap.md new file mode 100644 index 0000000..4f27332 --- /dev/null +++ b/Zammad/docs/adr/ADR-0002-oss-attachments-qnap.md @@ -0,0 +1,48 @@ +# ADR-0002: Attachment Zammad di QNAP OSS (Private Bucket) + +**Status:** Accepted +**Date:** 2026-07-02 + +--- + +## Context + +Zammad menyimpan lampiran tiket. Opsi storage: + +1. Disk lokal container/volume +2. S3-compatible object storage (QNAP QuObjects) +3. NFS share + +QNAP OSS sudah dipakai untuk `super-apps` (avatar publik) di geonet-console. + +--- + +## Decision + +- Bucket: **`zammad-attachments`** +- Endpoint: `http://10.100.1.10:8010` +- **Private** — tanpa public ACL atau nginx proxy publik +- Credential: reuse access key format `super-apps:` dari geonet-console `.env` +- Zammad config: Simple Storage (S3), `force_path_style: true` + +--- + +## Consequences + +**Positive** + +- Attachment tidak memenuhi disk root LVM di .24 +- Pola sama dengan stack existing (AWS SDK, QNAP) +- Backup NAS terpusat + +**Negative** + +- Ketergantungan jaringan internal ke QNAP +- QuObjects kadang `503` singkat setelah bucket baru — perlu retry + +--- + +## Related + +- [`server-connection/docs/adr/ADR-0004-qnap-object-storage.md`](../../../server-connection/docs/adr/ADR-0004-qnap-object-storage.md) +- [`docs/storage.md`](../storage.md) diff --git a/Zammad/docs/ai-session-summary.md b/Zammad/docs/ai-session-summary.md new file mode 100644 index 0000000..f8c784b --- /dev/null +++ b/Zammad/docs/ai-session-summary.md @@ -0,0 +1,20 @@ +# AI Session Summary + +```yaml +session: 2026-07-06-docs-bootstrap +project: Zammad/ +version: 7.1.1-0012.1 +status: ready +next: FE /ticketing + Mailcow email channel (Fase 3) +agent: Cursor +``` + +## TL;DR + +- Zammad live `zammad.gisportal.id`; LDAP 64 user; SMTP cPanel OK +- Bootstrap SSOT docs; Mailcow IMAP channel **belum** + +## Lanjut + +1. FE `/ticketing` (mysupperapps_FE_PWA) +2. Zammad channel → Mailcow `sync.geonet.co.id` diff --git a/Zammad/docs/api/overview.md b/Zammad/docs/api/overview.md new file mode 100644 index 0000000..8c37802 --- /dev/null +++ b/Zammad/docs/api/overview.md @@ -0,0 +1,51 @@ +# API Overview — Zammad REST + +> **Terakhir Diperbarui:** 2026-07-02 +> Dokumentasi resmi: https://docs.zammad.org/en/latest/api/intro.html + +--- + +## Base URL (target produksi) + +``` +https://zammad.gisportal.id/api/v1/ +``` + +--- + +## Autentikasi + +| Metode | Header | Use case | +|--------|--------|----------| +| **Token** | `Authorization: Token token=` | FE backend / integrasi | +| **Basic** | `Authorization: Basic ...` | Testing, admin tools | +| **OAuth** | *(opsional)* | Belum direncanakan | + +Token dibuat di Zammad: **Profile → Token Access** atau admin untuk service account. + +--- + +## Endpoint yang relevan untuk FE `/ticketing` + +| Method | Path | Keterangan | +|--------|------|------------| +| GET | `/tickets` | Daftar tiket user | +| POST | `/tickets` | Buat tiket baru | +| GET | `/tickets/{id}` | Detail tiket | +| POST | `/ticket_articles` | Balasan / komentar | +| GET | `/users/me` | User saat ini | +| GET | `/groups` | Group untuk routing | + +> Schema lengkap mengikuti versi Zammad yang diinstall — verifikasi setelah deploy. + +--- + +## Response format + +JSON. Error umum: `401` (token invalid), `422` (validasi), `500` (server). + +--- + +## Rate limiting + +Belum dikonfigurasi — rencana rate limit di nginx setelah go-live. diff --git a/Zammad/docs/architecture/authentication-flow.md b/Zammad/docs/architecture/authentication-flow.md new file mode 100644 index 0000000..1b639b8 --- /dev/null +++ b/Zammad/docs/architecture/authentication-flow.md @@ -0,0 +1,57 @@ +# Authentication Flow — Zammad + LDAP + +> **Terakhir Diperbarui:** 2026-07-02 + +--- + +## Alur login (target) + +```mermaid +sequenceDiagram + participant U as User + participant Z as Zammad UI + participant AD as AD 10.100.1.40 + + U->>Z: Login (username + password) + Z->>AD: LDAP bind + search user + AD-->>Z: OK + attributes (mail, cn, groups) + Z->>Z: Map group → Zammad role/group + Z-->>U: Session / JWT (Zammad internal) +``` + +--- + +## Integrasi FE (mysupperapps_FE_PWA) + +```mermaid +sequenceDiagram + participant FE as my.gisportal.id + participant GC as geonet-console + participant Z as Zammad API + + U->>FE: Buka /ticketing + FE->>GC: Login LDAP (existing flow) + FE->>Z: API calls dengan token layanan + Note over FE,Z: Token dari Zammad admin — bukan password user ke API +``` + +> Detail implementasi FE: `mysupperapps_FE_PWA/docs/` (belum dibuat). + +--- + +## LDAP parameters (referensi) + +| Parameter | Nilai | +|-----------|-------| +| Host | `10.100.1.40` | +| Port | `389` | +| Base DN | `DC=gisportal,DC=id` | +| User filter | Sesuaikan atribut AD (sAMAccountName) | + +Sinkronisasi group: petakan AD group ke Zammad **Group** untuk routing tiket. + +--- + +## Referensi + +- ADR LDAP umum: [`server-connection/docs/adr/ADR-0003-ldap-authentication.md`](../../../server-connection/docs/adr/ADR-0003-ldap-authentication.md) diff --git a/Zammad/docs/architecture/deployment-architecture.md b/Zammad/docs/architecture/deployment-architecture.md new file mode 100644 index 0000000..4255390 --- /dev/null +++ b/Zammad/docs/architecture/deployment-architecture.md @@ -0,0 +1,64 @@ +# Deployment Architecture — Zammad + +> **Terakhir Diperbarui:** 2026-07-02 + +--- + +## Topology + +``` +Internet + │ + ▼ +10.100.1.24 (proxy.lan) + ├── nginx :443 zammad.gisportal.id + └── /opt/stacks/zammad/ + ├── zammad-railsserver + ├── zammad-nginx (internal, upstream compose) + ├── zammad-elasticsearch + ├── zammad-redis + └── zammad-init (one-shot) + +10.100.1.25 (main-db) + └── PostgreSQL database: zammad + +10.100.1.10 (qnap) + └── QuObjects :8010 bucket zammad-attachments + +10.100.1.40 (AD) + └── LDAP :389 +``` + +--- + +## Keputusan deploy + +| Topik | Keputusan | +|-------|-----------| +| App host | `10.100.1.24` (sama dengan my-portal, geonet-console) | +| PostgreSQL | **Eksternal** di `10.100.1.25` — DB server murni | +| Elasticsearch | **Enabled** di compose (RAM 62 GB cukup) | +| Object storage | **S3** ke QNAP, bukan disk lokal untuk attachment | +| Jira VM `.55` | **Tidak dipakai** | + +--- + +## Path server + +| Item | Path | +|------|------| +| Compose stack | `/opt/stacks/zammad/` | +| Nginx vhost | `/etc/nginx/conf.d/production/zammad.conf` | +| OSS cred reference | `/opt/stacks/geonet-console/.env` | + +--- + +## Resource estimate (post-install) + +| Service | RAM (perkiraan) | +|---------|-----------------| +| Zammad Rails + workers | 2–4 GB | +| Elasticsearch | 4–8 GB | +| Redis | <512 MB | + +Monitor dengan `docker stats` setelah go-live. diff --git a/Zammad/docs/architecture/system-overview.md b/Zammad/docs/architecture/system-overview.md new file mode 100644 index 0000000..696d3be --- /dev/null +++ b/Zammad/docs/architecture/system-overview.md @@ -0,0 +1,61 @@ +# System Overview — Zammad dalam Super Apps + +> **Terakhir Diperbarui:** 2026-07-02 + +--- + +## Diagram + +```mermaid +flowchart LR + subgraph users [Users] + U[Browser / PWA] + end + + subgraph fe [Frontend] + MY[my.gisportal.id
mysupperapps_FE_PWA] + end + + subgraph zammad_stack [10.100.1.24 Docker] + Z[Zammad Rails] + ES[Elasticsearch] + RD[Redis] + end + + subgraph data [Data Layer] + PG[(PostgreSQL
10.100.1.25)] + OSS[(QNAP OSS
zammad-attachments)] + AD[(Active Directory
10.100.1.40)] + end + + U --> MY + MY -->|REST API token| Z + Z --> PG + Z --> ES + Z --> RD + Z --> OSS + Z -->|LDAP bind| AD + U -->|Admin UI optional| Z +``` + +--- + +## Boundary + +| Komponen | Owner repo | Catatan | +|----------|------------|---------| +| Zammad stack + nginx | `Zammad/` | Install & ops | +| UI ticketing end-user | `mysupperapps_FE_PWA` | Konsumsi API Zammad | +| LDAP / AD | infrastruktur | Shared dengan geonet-console | +| OSS credential | `server-connection` | Reuse key, bucket terpisah | +| Email inbound/outbound | Mailcow (belum) | Fase setelah POC web | + +--- + +## URL target + +| Service | URL | +|---------|-----| +| Zammad UI | `https://zammad.gisportal.id` | +| Zammad API | `https://zammad.gisportal.id/api/v1/` | +| FE ticketing | `https://my.gisportal.id/ticketing` | diff --git a/Zammad/docs/changelog.md b/Zammad/docs/changelog.md new file mode 100644 index 0000000..5e25547 --- /dev/null +++ b/Zammad/docs/changelog.md @@ -0,0 +1,56 @@ +# Changelog — Zammad + +--- + +## [7.1.1-0012.1] — 2026-07-06 + +### Added +- `AGENTS.md`, `.env.example`, `docs/version.md`, `docs/system-requirements.md`, `docs/guide/` +- `docs/ai-session-summary.md` + +--- + +--- + +## 2026-07-03 (SMTP selesai) + +- **SMTP outbound aktif** — `sc138.idcloudhosting.cloud:465` SSL, `support@geonet.co.id`, status `ok` +- Sender: `"Geonet Support" ` +- **Berikutnya:** FE `/ticketing` di mysupperapps_FE_PWA + +## 2026-07-03 (API token + SMTP prep) + +- **API token** `fe-ticketing-pwa` dibuat — permission ticket.agent/customer +- Token disimpan server: `/opt/stacks/zammad/.fe-ticketing-token` +- `GET /api/v1/tickets` verified HTTP 200 +- `notification_sender` diset ke `support@geonet.co.id` +- **SMTP DNS container fix** — `docker-compose.override.yml` dns resolver; TLS verify OK dari container + +--- +- Dokumen baru: `docs/notes/smtp-notification-setup.md`, `docs/notes/fe-ticketing-integration.md` +- Script: `scripts/test-smtp-connectivity.sh` +- Roadmap/todo/project-status diupdate — posisi: SMTP → FE → Mailcow → Webhook → KPI + +--- + +## 2026-07-02 (LDAP) + +- **LDAP dikonfigurasi** — source `GIS Portal AD` → AD `10.100.1.40:389` +- Integrasi LDAP diaktifkan di `System → Integrations → LDAP` +- First sync: 64 user diproses — 57 created, 1 updated, 3 skipped, 3 failed +- Dokumentasi diperbaiki: path menu Zammad 7 (`#system/integration/ldap`, bukan `#settings`) +- **Berikutnya:** role mapping, uji login AD, API token, FE `/ticketing` + +--- + +## 2026-07-02 + +- **Zammad 7.1.1-0012 deployed** di `10.100.1.24` — `https://zammad.gisportal.id` +- Stack: bundled PostgreSQL 17, Redis, Memcached, ES disabled, S3 `zammad-attachments` +- Nginx: `127.0.0.1:8093` → production vhost `zammad.conf` +- Blockers documented: PG 12 di `.25`, ES 9 CPU requirement + +- Repo `Zammad/` dibuat dengan struktur dokumentasi AI-native +- `docs/context-index.md` — entry point +- Bucket OSS `zammad-attachments` dibuat dan diverifikasi di QNAP +- Dokumentasi storage, deployment draft, ADR-0001/0002 diff --git a/Zammad/docs/context-index.md b/Zammad/docs/context-index.md new file mode 100644 index 0000000..4b61898 --- /dev/null +++ b/Zammad/docs/context-index.md @@ -0,0 +1,131 @@ +# Context Index — Zammad ⭐ AI Entry Point + +> **Terakhir Diperbarui:** 2026-07-06 +> **Versi:** 7.1.1-0012.1 — [version.md](./version.md) +> **Cold start:** [../AGENTS.md](../AGENTS.md) +> **Fase Aktif:** Fase 1b — SMTP notifikasi 🔄 → Fase 2 FE `/ticketing` + +--- + +## Filosofi + +Proyek ini menerapkan **AI Native Development**: +- Repository = sumber kebenaran utama (Single Source of Truth) +- AI tidak boleh mengandalkan riwayat percakapan +- Developer sering berpindah perangkat — konteks harus tersimpan di repo +- Implementasi tanpa dokumentasi = belum selesai + +--- + +## Urutan Membaca + +1. **File ini** — peta navigasi +2. `docs/project-status.md` — fase & status saat ini +3. `docs/todo.md` — next actions +4. Dokumen spesifik task (lihat tabel di bawah) +5. `perintah.md` — wajib dibaca sebelum menyatakan selesai + +--- + +## Posisi dalam Super Apps + +``` +my.gisportal.id (FE) ──API──► zammad.gisportal.id (Zammad REST) +geonet-console ──LDAP──► AD 10.100.1.40 (user/group sama) +Zammad attachments ──S3───► QNAP OSS zammad-attachments +Zammad DB ──PG───► 10.100.1.25 +``` + +| Repo terkait | Entry point | Kapan baca | +|--------------|-------------|------------| +| **mysupperapps_FE_PWA** | `docs/context-index.md` | Integrasi `/ticketing` UI | +| **server-connection** | `server-connection/docs/context-index.md` | LDAP, OSS credential, nginx pattern | +| **GeoNetAgent** | `GeoNetAgent/docs/context-index.md` | Kaitkan tiket ↔ asset (opsional) | + +--- + +## Peta Dokumentasi + +### `docs/` — Flat Files + +| File | Isi | Baca Saat | +|------|-----|-----------| +| `docs/project-status.md` | Status modul, milestone | Selalu | +| `docs/roadmap.md` | Fase super apps ticketing | Planning | +| `docs/todo.md` | Next actions berprioritas | Sebelum coding | +| `docs/issues.md` | Known bugs + workaround | Debug | +| `docs/changelog.md` | Riwayat perubahan | Reference | +| `docs/environment.md` | Env vars (tanpa secret) | Setup, deploy | +| `docs/server.md` | Server, SSH, stack path | Deploy, infra | +| `docs/deployment.md` | Step-by-step install Zammad | Deploy | +| `docs/storage.md` | QNAP OSS `zammad-attachments` | Attachment / S3 | +| `docs/troubleshooting.md` | Debug umum | Debug | +| `docs/security.md` | Credential, LDAP, token | Security | +| `docs/glossary.md` | Istilah Zammad + internal | Reference | + +### `docs/notes/` + +| File | Isi | +|------|-----| +| `email-geonet-co-id.md` | Parameter SMTP geonet.co.id + error historis | +| `smtp-notification-setup.md` | **Step-by-step SMTP Zammad 7** (fase aktif) | +| `fe-ticketing-integration.md` | Integrasi mysupperapps_FE_PWA `/ticketing` | +| `ldap-ad-setup.md` | LDAP Zammad → AD 10.100.1.40 | + +### `docs/architecture/` + +| File | Isi | +|------|-----| +| `system-overview.md` | Boundary Zammad vs FE vs Mailcow | +| `deployment-architecture.md` | Docker di 10.100.1.24, PG eksternal | +| `authentication-flow.md` | LDAP AD → Zammad user/role | + +### `docs/api/` + +| File | Isi | +|------|-----| +| `overview.md` | Zammad REST API, token, base URL | + +### `docs/adr/` + +| ADR | Keputusan | +|-----|-----------| +| `ADR-0001-zammad-ticketing-platform.md` | Zammad sebagai platform ticketing (bukan Jira .55) | +| `ADR-0002-oss-attachments-qnap.md` | Attachment di bucket private QNAP OSS | + +### `.cursor/rules/` + +| File | Isi | +|------|-----| +| `project-context.mdc` | Ringkasan proyek untuk AI | + +--- + +## Quick Reference + +| Fungsi | URL / Path | +|--------|------------| +| Zammad UI (target) | `https://zammad.gisportal.id` | +| Zammad API | `https://zammad.gisportal.id/api/v1/` | +| FE ticketing | `https://my.gisportal.id/ticketing` | +| OSS endpoint | `http://10.100.1.10:8010` | +| OSS bucket | `zammad-attachments` | +| Docker stack (target) | `/opt/stacks/zammad/` | + +### SSH + +```bash +ssh -m hmac-sha1 root@10.100.1.24 -p 22 +``` + +> SSH ke server **wajib minta persetujuan user** sebelum dijalankan. + +--- + +## Aturan Utama AI + +1. Baca `docs/context-index.md` ini terlebih dahulu +2. Jangan duplikasi dokumentasi OSS/LDAP — referensi ke `server-connection/docs/` bila umum +3. Perubahan deploy → update `docs/deployment.md` + `perintah.md` +4. ADR tidak boleh dihapus — buat baru jika keputusan berubah +5. **Jangan commit secret** (`.env`, token, LDAP password, OSS secret) diff --git a/Zammad/docs/deployment.md b/Zammad/docs/deployment.md new file mode 100644 index 0000000..c242d35 --- /dev/null +++ b/Zammad/docs/deployment.md @@ -0,0 +1,78 @@ +# Deployment — Zammad + +> **Terakhir Diperbarui:** 2026-07-02 +> **Status:** ✅ Installed 2026-07-02 — POC web live + +--- + +## Prasyarat + +- [x] Server `10.100.1.24` — RAM/disk/sysctl siap +- [x] Bucket OSS `zammad-attachments` +- [x] PostgreSQL — **bundled PG 17** di Docker (eksternal `.25` ditunda: PG 12) +- [x] DNS `zammad.gisportal.id` → IP publik (port 443) +- [x] SSL wildcard `*.gisportal.id` di nginx +- [x] Nginx vhost `/etc/nginx/conf.d/production/zammad.conf` + +--- + +## Fase 1 — Install (ringkas) + +### 1. Database PostgreSQL (10.100.1.25) + +```bash +ssh -m hmac-sha1 root@10.100.1.25 -p 22 +# Buat user + database zammad (detail saat implementasi) +``` + +### 2. Clone stack di 10.100.1.24 + +```bash +ssh -m hmac-sha1 root@10.100.1.24 -p 22 +mkdir -p /opt/stacks/zammad +cd /opt/stacks/zammad +git clone https://github.com/zammad/zammad-docker-compose.git . +cp .env.dist .env +# Edit .env: POSTGRES_*, ZAMMAD_FQDN, nonaktifkan bundled PG jika pakai eksternal +``` + +> Gunakan skenario upstream Zammad untuk **PostgreSQL eksternal** dan **Elasticsearch** sesuai dokumentasi resmi. + +### 3. S3 storage + +Salin `infra/zammad/storage.yml.example` → volume config Zammad, isi secret dari server. + +### 4. Start stack + +```bash +docker compose up -d +# Tunggu zammad-init selesai +``` + +### 5. Nginx + +Deploy `infra/nginx/zammad.gisportal.id.conf` → `/etc/nginx/conf.d/production/` + +```bash +nginx -t && nginx -s reload +``` + +### 6. Setup wizard + +Buka `https://zammad.gisportal.id` — admin pertama, LDAP, kategori tiket. + +--- + +## Rollback + +1. Snapshot VM Proxmox sebelum install, atau +2. `docker compose down` + hapus volume (data hilang) + restore DB backup + +--- + +## Post-deploy checklist + +- [ ] Login LDAP user uji +- [ ] Buat tiket + lampiran file → cek object di bucket OSS +- [ ] API token untuk FE (`/api/v1/`) +- [ ] Update `docs/project-status.md` + `perintah.md` diff --git a/Zammad/docs/environment.md b/Zammad/docs/environment.md new file mode 100644 index 0000000..22da59b --- /dev/null +++ b/Zammad/docs/environment.md @@ -0,0 +1,70 @@ +# Environment Variables — Zammad + +> **Terakhir Diperbarui:** 2026-07-02 +> ⚠️ **Jangan commit nilai secret.** File `.env` hanya di server `/opt/stacks/zammad/`. + +--- + +## Zammad Docker (target) + +| Variable | Contoh | Keterangan | +|----------|--------|------------| +| `POSTGRES_HOST` | `10.100.1.25` | PostgreSQL eksternal | +| `POSTGRES_PORT` | `5432` | | +| `POSTGRES_USER` | `zammad` | User dedicated | +| `POSTGRES_PASS` | **SECRET** | Password DB | +| `POSTGRES_DB` | `zammad` | Nama database | +| `REDIS_URL` | `redis://zammad-redis:6379` | Internal compose | +| `ELASTICSEARCH_URL` | `http://zammad-elasticsearch:9200` | Internal compose | +| `ZAMMAD_FQDN` | `zammad.gisportal.id` | Hostname publik | + +--- + +## S3 Storage (QNAP OSS) + +| Variable | Nilai | Keterangan | +|----------|-------|------------| +| `S3_URL` | *(lihat storage.yml)* | Atau file `storage.yml` | +| Endpoint | `http://10.100.1.10:8010` | Internal dari server .24 | +| Bucket | `zammad-attachments` | Private | +| Access key format | `super-apps:` | Reuse credential geonet-console | +| Secret | **SECRET** | Dari `/opt/stacks/geonet-console/.env` | +| `force_path_style` | `true` | Wajib untuk QNAP | + +Contoh `storage.yml` (nilai secret dari server, bukan repo): + +```yaml +s3: + access_key_id: 'super-apps:' + secret_access_key: '' + region: 'us-east-1' + endpoint: 'http://10.100.1.10:8010' + bucket: 'zammad-attachments' + force_path_style: true + request_checksum_calculation: when_required + response_checksum_validation: when_required +``` + +--- + +## LDAP (Active Directory) + +| Variable | Nilai | +|----------|-------| +| LDAP host | `10.100.1.40` | +| LDAP port | `389` | +| Base DN | `DC=gisportal,DC=id` | +| Bind DN | `Administrator@gisportal.id` *(atau service account)* | +| Bind password | **SECRET** | + +> Detail LDAP mengikuti pola `server-connection/docs/environment.md`. + +--- + +## Lokasi Secret + +| Secret | Lokasi | +|--------|--------| +| Zammad `.env` | `/opt/stacks/zammad/.env` di 10.100.1.24 | +| OSS secret (reuse) | `/opt/stacks/geonet-console/.env` | +| LDAP bind | Zammad `.env` atau UI admin (prefer env) | diff --git a/Zammad/docs/glossary.md b/Zammad/docs/glossary.md new file mode 100644 index 0000000..563b6aa --- /dev/null +++ b/Zammad/docs/glossary.md @@ -0,0 +1,14 @@ +# Glossary — Zammad + +| Istilah | Arti | +|---------|------| +| **Zammad** | Platform open-source helpdesk / ticketing (Ruby on Rails) | +| **Ticket** | Unit pekerjaan support (incident, request, dll.) | +| **Group** | Tim penanganan tiket di Zammad; biasanya dipetakan dari AD group | +| **Organization** | Entitas pelanggan/internal di Zammad | +| **LDAP** | Active Directory di `10.100.1.40` untuk autentikasi user | +| **OSS / QuObjects** | Object storage S3-compatible di QNAP `10.100.1.10:8010` | +| **zammad-attachments** | Bucket private untuk file lampiran tiket | +| **FE `/ticketing`** | Halaman my.gisportal.id untuk buat/lihat tiket via API Zammad | +| **Mailcow** | Mail server terencana; channel email Zammad (fase berikutnya) | +| **geonet-console** | Backend Laravel; sumber reuse credential OSS `super-apps` | diff --git a/Zammad/docs/guide/README.md b/Zammad/docs/guide/README.md new file mode 100644 index 0000000..f3e05f1 --- /dev/null +++ b/Zammad/docs/guide/README.md @@ -0,0 +1,8 @@ +# Guides — Zammad + +| Guide | Path | +|-------|------| +| Migrasi | [migration.md](./migration.md) | +| Deploy | [../deployment.md](../deployment.md) | +| Storage OSS | [../storage.md](../storage.md) | +| FE ticketing | [../notes/fe-ticketing-integration.md](../notes/fe-ticketing-integration.md) | diff --git a/Zammad/docs/guide/migration.md b/Zammad/docs/guide/migration.md new file mode 100644 index 0000000..d84a550 --- /dev/null +++ b/Zammad/docs/guide/migration.md @@ -0,0 +1,26 @@ +# Migration Guide — Zammad + +## Host saat ini + +| Item | Nilai | +|------|-------| +| Stack | `/opt/stacks/zammad` | +| Server | `10.100.1.24` | +| Public URL | `https://zammad.gisportal.id` | +| Backend port | `8093` | + +## Migrasi email ke Mailcow (Fase 3) + +1. Pastikan Mailcow live (`Mailcow/docs/project-status.md`) +2. Zammad Admin → Channel Email: + - IMAP `sync.geonet.co.id:993` → `support@geonet.co.id` + - SMTP `sync.geonet.co.id:587` STARTTLS +3. Matikan SMTP cPanel setelah verified +4. Append [../version.md](../version.md) + +## Migrasi server + +1. Backup PG + `/opt/stacks/zammad` +2. Deploy stack di host baru +3. Update nginx upstream +4. Update DNS `zammad.gisportal.id` diff --git a/Zammad/docs/issues.md b/Zammad/docs/issues.md new file mode 100644 index 0000000..2e2af75 --- /dev/null +++ b/Zammad/docs/issues.md @@ -0,0 +1,98 @@ +# Issues — Zammad + +> **Terakhir Diperbarui:** 2026-07-02 + +--- + +## Known Issues + +### PostgreSQL 10.100.1.25 — PG 12, tidak kompatibel Zammad 7 + +- **Status:** Blocker untuk DB eksternal di `.25` +- **Gejala:** `zammad-init` loop / migrasi gagal saat `POSTGRES_HOST=10.100.1.25` +- **Penyebab:** Server `.25` menjalankan **PostgreSQL 12.12**; Zammad 7 membutuhkan **PostgreSQL 13+** +- **Workaround saat ini:** Gunakan **bundled PostgreSQL 17** di stack Docker (`zammad-postgresql` container) +- **Solusi jangka panjang:** Upgrade PG di `.25` ke 13+ lalu migrasi DB Zammad + +### Elasticsearch 9 — CPU tidak support x86-64-v2 + +- **Status:** ES dinonaktifkan (`ELASTICSEARCH_ENABLED=false`) +- **Gejala:** Container `zammad-elasticsearch` crash: `Fatal glibc error: CPU does not support x86-64-v2` +- **Dampak:** Full-text search Zammad terbatas / nonaktif sampai ES kompatibel +- **Opsi:** Upgrade CPU VM Proxmox (host flags), atau deploy ES versi lama di host terpisah + +### storage.yml permission (container user zammad) + +- **Status:** Fixed saat install +- **Gejala:** `Permission denied @ rb_sysopen - /opt/zammad/config/storage.yml` +- **Fix:** `chmod 644 config/storage.yml` di host (bukan `600` root-only) + +### CSRF token verification failed (setup wizard) + +- **Status:** Fixed 2026-07-02 +- **Gejala:** Error saat Create admin di wizard `https://zammad.gisportal.id` +- **Penyebab:** Nginx host terminate SSL; Zammad internal nginx pakai `$scheme` = `http` → cookie secure tidak cocok +- **Fix:** Tambah `NGINX_SERVER_SCHEME=https` + `NGINX_SERVER_NAME=zammad.gisportal.id` di `.env`, restart stack +- **Ref:** [Zammad env vars](https://docs.zammad.org/en/latest/appendix/environment-variables.html) + +### OSS upload 503 immediately after bucket create + +- **Status:** Known / workaround +- **Gejala:** `PutObject` gagal `503 Service Unavailable` tepat setelah `createBucket` +- **Penyebab:** QNAP QuObjects perlu waktu singkat setelah container baru dibuat +- **Workaround:** Retry 3–5x dengan jeda 3 detik (lihat `scripts/oss-create-bucket.php`) + +--- + +### LDAP sync — 3 user failed, 3 skipped + +- **Status:** Open — minor, tidak blocking +- **Gejala:** First sync 64 user — 3 failed, 3 skipped +- **Penyebab umum:** atribut `mail` kosong di AD, akun service/disabled, duplikasi email +- **Tindakan:** Cek di `System → Integrations → LDAP` → Recent Logs; perbaiki AD; **Start new** + +### LDAP menu tidak muncul / URL tidak respon + +- **Status:** Fixed 2026-07-02 +- **Gejala:** User cari LDAP di `Settings → Security` (SAML) atau URL `#settings/integration/ldap` +- **Penyebab:** Zammad 7 memisahkan menu **Settings** vs **System**; LDAP ada di `System → Integrations` +- **Fix:** Gunakan `https://zammad.gisportal.id/#system/integration/ldap` + +--- + +### SMTP — SSL_read unexpected eof / DNS gagal di container + +- **Status:** Fixed 2026-07-03 +- **Gejala:** + - `sc138.idcloudhosting.cloud` (465/587): `SSL_read: unexpected eof while reading` + - `sc138.idcloudhosting.cloud` (587): `getaddrinfo: No address associated with hostname` +- **Penyebab:** DNS di dalam container Docker Zammad (`127.0.0.11`) **tidak bisa resolve** hostname eksternal. Koneksi SMTP gagal sebelum/saat TLS handshake. +- **Fix:** Tambah DNS resolver host di `docker-compose.override.yml`: + ```yaml + dns: + - 203.142.82.222 + - 203.142.84.222 + ``` + pada `zammad-railsserver`, `zammad-scheduler`, `zammad-websocket`, `zammad-nginx` — lalu `docker compose up -d`. +- **Setelah fix:** Uji ulang SMTP di **Channels → Email** dengan: + +| Field | Nilai | +|-------|-------| +| Host | `sc138.idcloudhosting.cloud` | +| Port | `465` | +| SSL | Yes (implicit) | +| SSL verification | Yes | +| User | `support@geonet.co.id` | + +> Port **587** = STARTTLS (bukan SSL implicit) — jika dipakai, mode SSL harus **STARTTLS**, bukan SSL. + +--- + +## Fixed + +| Issue | Tanggal | +|-------|---------| +| SMTP DNS container Docker | 2026-07-03 | +| LDAP menu / URL salah | 2026-07-02 | +| CSRF setup wizard | 2026-07-02 | +| storage.yml permission | 2026-07-02 | diff --git a/Zammad/docs/notes/email-geonet-co-id.md b/Zammad/docs/notes/email-geonet-co-id.md new file mode 100644 index 0000000..975860b --- /dev/null +++ b/Zammad/docs/notes/email-geonet-co-id.md @@ -0,0 +1,121 @@ +# Catatan Email — geonet.co.id (Zammad SMTP) + +> **Terakhir Diperbarui:** 2026-07-02 +> **Status setup wizard:** Email notification **di-skip** (POC OK). Admin: `support@geonet.co.id`. +> ⚠️ **Jangan commit password.** Simpan password hanya di password manager / input wizard Zammad. + +--- + +## Akun yang dipakai + +| Item | Nilai | +|------|-------| +| Alamat email | `support@geonet.co.id` | +| Password | *(password akun email — tidak didokumentasikan di repo)* | + +--- + +## Pengaturan resmi geonet.co.id (Recommended — SSL/TLS) + +| Arah | Server | Port | Protokol | +|------|--------|------|----------| +| **Outgoing SMTP** | `mail.geonet.co.id` | **465** | SSL/TLS (implicit) | +| Incoming IMAP | `mail.geonet.co.id` | 993 | SSL/TLS | +| Incoming POP3 | `mail.geonet.co.id` | 995 | SSL/TLS | + +Alternatif SMTP (STARTTLS, tidak diprioritaskan jika 465 gagal dari server): + +| Outgoing SMTP | `mail.geonet.co.id` | **587** | STARTTLS | + +Semua protokol **wajib autentikasi** (username = alamat email penuh). + +--- + +## Pengaturan alternatif (cPanel / idcloudhosting) + +Beberapa client menampilkan hostname backend: + +| Item | Nilai | +|------|-------| +| Incoming (POP3) | `sc138.idcloudhosting.cloud:995` SSL | +| Outgoing (SMTP) | `sc138.idcloudhosting.cloud:465` SSL | + +> `sc138.idcloudhosting.cloud` dan `mail.geonet.co.id` biasanya server yang sama (CNAME/alias). +> **Utamakan `mail.geonet.co.id`** — lebih stabil untuk konfigurasi aplikasi. + +--- + +## Isian Zammad — Email Notification (setup wizard) + +Pilih: **SMTP — configure your own outgoing SMTP setting** + +### Kombinasi yang disarankan (setelah wizard) + +| Field Zammad | Isi | +|--------------|-----| +| **Host** | `sc138.idcloudhosting.cloud` | +| **User** | `support@geonet.co.id` | +| **Password** | *(password akun email)* | +| **Port** | `465` | +| **SSL verification** | `yes` *(cert cocok dengan hostname `sc138`)* | +| **Sender / From** | `support@geonet.co.id` *(wajib sebelum test kirim)* | + +> Jangan pakai `mail.geonet.co.id` + SSL verify **yes** — cert server untuk hostname `sc138`, bukan `mail` → hostname mismatch. + +### Alternatif (kurang ideal) + +| Host | Port | SSL verification | +|------|------|----------------| +| `mail.geonet.co.id` | 465 | **no** *(hanya jika cert tidak bisa diperbaiki di hosting)* | + +### Jika masih timeout + +Kemungkinan **firewall server `10.100.1.24`** memblokir outbound SMTP (465/587). +Cek dari server: + +```bash +nc -zv -w5 mail.geonet.co.id 465 +nc -zv -w5 mail.geonet.co.id 587 +``` + +Jika timeout dari server tapi OK dari laptop → buka outbound SMTP di firewall MikroTik / host. + +**Workaround POC:** klik **Skip** di wizard — notifikasi email dikonfigurasi ulang setelah Mailcow (roadmap fase berikutnya). + +--- + +## Roadmap email Super Apps + +| Fase | Platform | +|------|----------| +| Sekarang (POC) | SMTP `support@geonet.co.id` via `mail.geonet.co.id` *(opsional)* | +| Berikutnya | **Mailcow** — Zammad channel email inbound/outbound terpusat | + +--- + +### DNS Docker container (SMTP gagal) + +Jika error `getaddrinfo` atau `SSL_read: unexpected eof` dari **dalam** Zammad padahal `nc` dari host OK — DNS container rusak. + +**Fix:** `infra/zammad/docker-compose.override.yml` — tambah `dns: [203.142.82.222, 203.142.84.222]` lalu recreate container. + +--- + +## Error yang pernah terjadi (2026-07-02) + +| Error | Host | Penyebab | Solusi | +|-------|------|----------|--------| +| `port 587 timed out` | `sc138...` | Port 587 lambat/diblok | Pakai port **465** | +| `certificate verify failed (hostname mismatch)` | `mail.geonet.co.id:465` | Cert SSL untuk `sc138.idcloudhosting.cloud`, bukan `mail.geonet.co.id` | Host → `sc138...` + SSL yes, **atau** `mail...` + SSL **no** | +| `SSL_read: unexpected eof` / `getaddrinfo` | `sc138` 465/587 | DNS container Docker gagal resolve hostname | Fix DNS di `docker-compose.override.yml` — lihat `docs/issues.md` | +| `550 From domain must match authenticated domain` | `sc138...:465` | From bukan `@geonet.co.id` | Set **sender** = `support@geonet.co.id` dulu | + +**Keputusan POC:** Skip email di wizard — Zammad tetap jalan tanpa notifikasi email sampai Mailcow atau SMTP diperbaiki. + +### Lokasi konfigurasi ulang (setelah wizard) + +**Admin → Channels → Email** — bagian Email Notification (SMTP) + +URL: `https://zammad.gisportal.id/#channels/email` + +Panduan lengkap step-by-step: [`smtp-notification-setup.md`](smtp-notification-setup.md) diff --git a/Zammad/docs/notes/fe-ticketing-integration.md b/Zammad/docs/notes/fe-ticketing-integration.md new file mode 100644 index 0000000..58a0253 --- /dev/null +++ b/Zammad/docs/notes/fe-ticketing-integration.md @@ -0,0 +1,115 @@ +# FE `/ticketing` — Integrasi mysupperapps_FE_PWA + +> **Terakhir Diperbarui:** 2026-07-03 +> **Status:** 📋 Fase 2 — setelah SMTP (atau paralel jika SMTP ditunda) +> **Repo FE:** `mysupperapps_FE_PWA` *(repo terpisah)* + +--- + +## Arsitektur + +``` +my.gisportal.id/ticketing ──HTTPS──► Zammad REST API + │ │ + └── JWT geonet-console (user AD) └── Token token= +``` + +User login via geonet-console (LDAP AD). FE memanggil Zammad API dengan service token atau user token. + +--- + +## Prasyarat Zammad (server) + +| Item | Status | +|------|--------| +| Zammad live `https://zammad.gisportal.id` | ✅ | +| LDAP AD sync | ✅ | +| API token admin / service | ✅ `fe-ticketing-pwa` (2026-07-03) — lihat server | +| Group & kategori tiket | 📋 Belum | +| SMTP notifikasi | ✅ `sc138.idcloudhosting.cloud:465` | + +--- + +## Step — Sisi Zammad + +### 1. API token — ✅ dibuat 2026-07-03 + +| Field | Nilai | +|-------|-------| +| Name | `fe-ticketing-pwa` | +| User | `support@geonet.co.id` | +| Permission | `ticket.agent`, `ticket.customer`, `admin.ticket` | +| Lokasi server | `/opt/stacks/zammad/.fe-ticketing-token` *(chmod 600, jangan commit)* | + +Ambil token dari server: + +```bash +ssh root@10.100.1.24 "cat /opt/stacks/zammad/.fe-ticketing-token" +``` + +Atau lihat di UI: **Profile → Token Access** (nama `fe-ticketing-pwa`). + +**Uji API** — sudah diverifikasi `GET /api/v1/tickets` → HTTP 200. + +```bash +curl -s -H "Authorization: Token token=" \ + https://zammad.gisportal.id/api/v1/tickets?per_page=5 +``` + +### 3. Group untuk routing tiket + +**Manage → Groups** — pastikan group default (mis. `Users`) ada untuk customer create ticket. + +--- + +## Step — Sisi FE (mysupperapps_FE_PWA) + +| Task | File / lokasi | +|------|----------------| +| Client HTTP Zammad | `src/lib/zammad-client.ts` | +| Halaman list tiket | `/ticketing` route | +| Form buat tiket | POST `/api/v1/tickets` | +| Detail + balasan | GET ticket + POST `ticket_articles` | + +Env FE (contoh): + +```env +VITE_ZAMMAD_BASE_URL=https://zammad.gisportal.id +VITE_ZAMMAD_API_TOKEN= +``` + +> Pertimbangan produksi: token di backend proxy (BFF), bukan di browser — evaluasi saat implementasi. + +--- + +## Endpoint utama + +Lihat [`docs/api/overview.md`](../api/overview.md). + +| Method | Path | Use case FE | +|--------|------|-------------| +| GET | `/tickets` | Daftar tiket user | +| POST | `/tickets` | Buat tiket baru | +| GET | `/tickets/{id}` | Detail | +| POST | `/ticket_articles` | Komentar / balasan | +| GET | `/users/me` | Profil user Zammad | +| GET | `/groups` | Pilihan group | + +--- + +## Urutan implementasi disarankan + +1. Token + curl test dari server/dev +2. `zammad-client.ts` — wrapper fetch + error handling +3. Halaman list tiket (read-only) +4. Form create ticket +5. Detail ticket + articles +6. Polish UI + error states + +--- + +## Setelah FE OK + +- [ ] Update `docs/project-status.md` +- [ ] Fase 3: Mailcow (email inbound) +- [ ] Fase 4: Webhook → geonet-push diff --git a/Zammad/docs/notes/ldap-ad-setup.md b/Zammad/docs/notes/ldap-ad-setup.md new file mode 100644 index 0000000..d8fcd3f --- /dev/null +++ b/Zammad/docs/notes/ldap-ad-setup.md @@ -0,0 +1,180 @@ +# LDAP — Zammad ke Active Directory + +> **Terakhir Diperbarui:** 2026-07-02 +> **AD:** `10.100.1.40` · domain `gisportal.id` +> ⚠️ Bind password **tidak** didokumentasikan di repo — sama dengan `geonet-console` `.env` + +--- + +## Prasyarat + +- [x] Zammad setup wizard selesai (admin `support@geonet.co.id`) +- [x] Koneksi TCP `10.100.1.40:389` dari container Zammad +- [x] LDAP bind + search uji dari container (`BIND_OK`, `SEARCH_OK`) +- [x] LDAP source `GIS Portal AD` dikonfigurasi & first sync selesai (2026-07-02) + +--- + +## Test koneksi (sudah diverifikasi 2026-07-02) + +Dari server `10.100.1.24`: + +```bash +# TCP +nc -zv -w5 10.100.1.40 389 + +# Bind + search (script di /tmp/ldap-test.rb via rails runner) +source /opt/stacks/geonet-console/.env +docker exec -e LDAP_HOST -e LDAP_PORT -e LDAP_BASE_DN -e LDAP_BIND_DN -e LDAP_BIND_PASSWORD \ + zammad-zammad-railsserver-1 bundle exec rails runner /tmp/ldap-test.rb +# Harapan: BIND_OK + SEARCH_OK +``` + +Credential bind **reuse** dari `/opt/stacks/geonet-console/.env` (sama dengan geonet-console). + +--- + +## Step-by-step — UI Zammad + +Login admin → **https://zammad.gisportal.id** + +### Langkah 1 — Buka menu LDAP (Zammad 7) + +⚠️ **Penting — jangan salah menu:** + +| Lokasi | Isi | LDAP? | +|--------|-----|-------| +| **Settings** → **Security** → *Third-party applications* | SAML, SSO | ❌ Bukan di sini | +| **Settings** → **System** | Base, Storage, Network, Frontend | ❌ Bukan di sini | +| **System** → **Integrations** | LDAP, GitHub, Exchange, … | ✅ **Di sini** | + +Di Zammad 7 ada **dua menu terpisah** di panel Admin (ikon ⚙️): + +1. **Settings** (`#settings`) — branding, security, ticket, dll. +2. **System** (`#system`) — integrations, API, maintenance, dll. + +LDAP ada di menu **System** (bukan di dalam Settings → System). + +Path yang benar: + +**Admin** (⚙️) → **System** → **Integrations** → klik **LDAP** + +Atau langsung buka URL: + +``` +https://zammad.gisportal.id/#system/integration/ldap +``` + +> URL `#settings/integration/ldap` **tidak ada** di Zammad 7 — itu penyebab halaman tidak merespons. + +Klik **New Source** untuk menambah sumber LDAP baru. + +> Referensi resmi: [Zammad Admin — LDAP / Active Directory](https://admin-docs.zammad.org/en/latest/system/integrations/ldap/) + +--- + +### Langkah 2 — Connection + +| Field UI | Nilai | +|----------|-------| +| **Name** | `GIS Portal AD` | +| **Host** | `10.100.1.40` | +| **Port** | `389` | +| **SSL** | **Off** / unchecked *(sama geonet-console: `LDAP_USE_SSL=false`)* | +| **Base DN** | `DC=gisportal,DC=id` | +| **Bind user** | `Administrator@gisportal.id` | +| **Bind password** | *(dari `.env` geonet-console — `LDAP_BIND_PASSWORD`)* | + +Klik **Test connection** jika ada — harus sukses. + +--- + +### Langkah 3 — User filter & attributes + +| Field UI | Nilai | +|----------|-------| +| **User filter** | `(&(objectClass=user)(objectCategory=person))` | +| **Login attribute** | `sAMAccountName` | +| **Email attribute** | `mail` | +| **Firstname** | `givenName` | +| **Lastname** | `sn` | +| **Username attribute** | `sAMAccountName` | + +Opsi yang disarankan: + +- **Sync users on login** — ✅ aktif +- **Create user on login** — ✅ aktif (user AD otomatis dibuat di Zammad) + +--- + +### Langkah 4 — Role / group mapping (disarankan) + +Setelah user AD bisa login, petakan AD group → Zammad role: + +| AD group (contoh) | Zammad role | +|-------------------|-------------| +| `Domain Admins` / `IT-Admin` *(sesuaikan)* | **Admin** | +| `Domain Users` atau group support | **Agent** | +| *(default)* | **Customer** | + +Di LDAP config Zammad, bagian **Role mapping** / **Group mapping**: + +- Attribute group: `memberOf` +- Filter group: `(objectClass=group)` + +> Nama group AD cek di AD atau geonet-console → LDAP Users/Groups. + +--- + +### Langkah 5 — Aktifkan LDAP login + +- Set LDAP sebagai metode login (nonaktifkan signup publik jika ada) +- **Settings → System → Login** — pastikan hanya LDAP / AD untuk user internal + +--- + +### Langkah 6 — Uji login + +1. **Logout** dari admin Zammad +2. Login dengan user AD uji, mis. `sAMAccountName` + password AD *(bukan email, kecuali UI minta UPN)* +3. Cek **Manage → Users** — user AD muncul setelah login pertama + +--- + +## Parameter referensi (geonet-console) + +| Env geonet-console | Nilai | +|--------------------|-------| +| `LDAP_HOST` | `10.100.1.40` | +| `LDAP_PORT` | `389` | +| `LDAP_BASE_DN` | `DC=gisportal,DC=id` | +| `LDAP_BIND_DN` | `Administrator@gisportal.id` | +| `LDAP_GROUP_CONTAINER_DN` | `CN=Users,DC=gisportal,DC=id` | +| `LDAP_ADMIN_GROUPS` | `Domain Admins,Administrators,Enterprise Admins` | + +--- + +## Troubleshooting + +| Gejala | Penyebab | Tindakan | +|--------|----------|----------| +| LDAP tidak ada di menu | Salah buka **Settings → Security** atau **Settings → System** | Buka **System → Integrations** (menu terpisah, bukan di dalam Settings) | +| URL `#settings/integration/ldap` tidak respon | Route Zammad 7 pakai `#system`, bukan `#settings` | Pakai `https://zammad.gisportal.id/#system/integration/ldap` | +| Hanya SAML/SSO di Third-party | Itu menu autentikasi SAML, bukan LDAP sync | LDAP ada di **System → Integrations** | +| Test connection gagal | Bind password salah | Cek `/opt/stacks/geonet-console/.env` | +| Login gagal, bind OK | Login attribute salah | Pakai `sAMAccountName`, bukan email | +| User tanpa email | Atribut `mail` kosong di AD | Isi mail di AD atau fallback di Zammad | +| Tidak bisa reach AD | Firewall | Pastikan `.24` → `.40:389` (sudah OK) | + +--- + +## Setelah LDAP OK + +- [x] Update `docs/project-status.md` — LDAP ✅ (2026-07-02) +- [ ] Role mapping AD group → Zammad role +- [ ] Uji login user AD (`sAMAccountName`) +- [ ] Tindak 3 user gagal sync (cek `mail` di AD) +- [ ] Buat **API token** untuk FE `/ticketing` +- [ ] Lanjut `mysupperapps_FE_PWA` — halaman `/ticketing` + +Lihat `docs/roadmap.md` dan `docs/todo.md` untuk urutan lengkap. diff --git a/Zammad/docs/notes/smtp-notification-setup.md b/Zammad/docs/notes/smtp-notification-setup.md new file mode 100644 index 0000000..00a2f1a --- /dev/null +++ b/Zammad/docs/notes/smtp-notification-setup.md @@ -0,0 +1,106 @@ +# SMTP Notifikasi — Zammad 7 + +> **Terakhir Diperbarui:** 2026-07-03 +> **Status:** ✅ Selesai 2026-07-03 +> **Akun:** `support@geonet.co.id` +> ⚠️ Password **tidak** didokumentasikan di repo + +--- + +## Prasyarat (sudah diverifikasi 2026-07-03) + +| Cek | Hasil | +|-----|-------| +| Port 465 `sc138.idcloudhosting.cloud` dari `.24` | ✅ Reachable | +| Port 587 `sc138.idcloudhosting.cloud` dari `.24` | ✅ Reachable | +| Port 465 `mail.geonet.co.id` dari `.24` | ✅ Reachable | +| SSL cert SMTP | `CN=*.idcloudhosting.cloud` (DigiCert) — pakai hostname `sc138...` + verify **yes** | +| Channel aktif saat ini | `sendmail` *(tidak mengirim email nyata dari Docker)* | + +Detail error historis: [`email-geonet-co-id.md`](email-geonet-co-id.md) + +--- + +## Langkah 1 — Set Notification Sender + +Sebelum test SMTP, ubah **From address** dari default sistem. + +1. Login admin → https://zammad.gisportal.id +2. **Admin** (⚙️) → **Channels** → **Email** +3. Di bagian **Notification** (atau buka wizard notifikasi), set **Sender**: + +``` +"Geonet Support" +``` + +Atau via **Settings** → cari setting **Notification Sender** (`notification_sender`). + +> **Penting:** From wajib domain `@geonet.co.id`. Jika masih `noreply@zammad.gisportal.id`, SMTP hosting menolak dengan error `550 From domain must match authenticated domain`. + +--- + +## Langkah 2 — Konfigurasi SMTP outbound + +**Admin** → **Channels** → **Email** → bagian **Email Notification** + +Pilih: **SMTP — configure your own outgoing SMTP setting** + +| Field Zammad | Nilai | +|--------------|-------| +| **Adapter** | SMTP | +| **Host** | `sc138.idcloudhosting.cloud` | +| **Port** | `465` | +| **SSL** | ✅ Yes (implicit SSL) | +| **SSL verification** | ✅ Yes | +| **User** | `support@geonet.co.id` | +| **Password** | *(password akun email — input manual)* | + +Klik **Save** / **Test** — Zammad memanggil probe outbound; jika sukses, konfigurasi tersimpan otomatis. + +**URL langsung:** `https://zammad.gisportal.id/#channels/email` + +### Alternatif (jika 465 gagal) + +| Host | Port | SSL | SSL verify | +|------|------|-----|------------| +| `mail.geonet.co.id` | 465 | Yes | **No** *(cert mismatch)* | +| `sc138.idcloudhosting.cloud` | 587 | STARTTLS | Yes | + +--- + +## Langkah 3 — Verifikasi + +1. **Test** dari wizard SMTP — harus `result: ok` +2. Buat tiket uji → assign ke agent → cek agent menerima email notifikasi +3. Cek channel status di **Channels → Email** — outbound status `ok` + +### Cek dari server (opsional) + +```bash +# Konektivitas +nc -zv -w5 sc138.idcloudhosting.cloud 465 + +# Status channel (tanpa password) +docker exec zammad-zammad-railsserver-1 bundle exec rails runner \ + "Channel.where(area: 'Email::Notification').each { |c| puts \"id=#{c.id} active=#{c.active} adapter=#{c.options.dig(:outbound,:adapter)} status=#{c.status_out}\" }" +``` + +--- + +## Setelah SMTP OK + +- [ ] Update `docs/project-status.md` — SMTP ✅ +- [ ] Lanjut **API token** + FE `/ticketing` — lihat [`fe-ticketing-integration.md`](fe-ticketing-integration.md) +- [ ] Nanti (Fase Mailcow): ganti SMTP ke Mailcow internal + +--- + +## Troubleshooting + +| Error | Penyebab | Solusi | +|-------|----------|--------| +| `550 From domain must match` | Sender bukan `@geonet.co.id` | Set `notification_sender` dulu | +| `certificate verify failed (hostname mismatch)` | Host `mail.geonet.co.id`, cert untuk `sc138` | Host → `sc138.idcloudhosting.cloud` | +| `port 587 timed out` | Lambat / intermittent | Pakai port **465** | +| Test OK tapi tidak ada email | Spam folder / sendmail masih aktif | Pastikan channel SMTP **active**, sendmail **inactive** | +| `authentication failed` | Password salah | Reset password di cPanel / hosting | diff --git a/Zammad/docs/project-status.md b/Zammad/docs/project-status.md new file mode 100644 index 0000000..5ad3fb2 --- /dev/null +++ b/Zammad/docs/project-status.md @@ -0,0 +1,57 @@ +# Project Status — Zammad + +> **Terakhir Diperbarui:** 2026-07-03 + +--- + +## Snapshot + +| Item | Status | +|------|--------| +| **Fase** | Fase 1b selesai → **Fase 2 FE `/ticketing`** | +| **Zammad running** | ✅ `https://zammad.gisportal.id` | +| **LDAP / AD** | ✅ `GIS Portal AD` — sync 64 user | +| **OSS bucket** | ✅ `zammad-attachments` | +| **PostgreSQL** | ✅ Bundled PG 17 | +| **Nginx** | ✅ `zammad.gisportal.id` → `127.0.0.1:8093` | +| **Elasticsearch** | ⚠️ Disabled | +| **API token (FE)** | ✅ `fe-ticketing-pwa` — `/opt/stacks/zammad/.fe-ticketing-token` | +| **SMTP notifikasi** | ✅ `sc138.idcloudhosting.cloud:465` SSL — `support@geonet.co.id` | +| **Feedback → Zammad sync** | ✅ geonet-console `ZammadTicketService` | +| **Mailcow** | 📋 Fase 3 | +| **Webhook push** | 📋 Fase 4 | +| **KPI dashboard** | 📋 Fase 5 | + +--- + +## Selesai + +| # | Item | Tanggal | +|---|------|---------| +| 1 | Deploy Zammad 7.1.1-0012 + nginx + OSS | 2026-07-02 | +| 2 | Setup wizard + LDAP `GIS Portal AD` | 2026-07-02 | +| 4 | SMTP outbound `support@geonet.co.id` (SSL 465) | 2026-07-03 | + +--- + +## Berikutnya (urutan fase) + +| # | Item | Ref | +|---|------|-----| +| **8** | **FE `/ticketing`** ← *posisi saat ini* | `fe-ticketing-integration.md` | +| 9 | Mailcow + email channel inbound | `docs/roadmap.md` Fase 3 | +| 10 | Webhook → geonet-push | Fase 4 | +| 11 | KPI dashboard | Fase 5 | + +Detail task: [`todo.md`](todo.md) · [`roadmap.md`](roadmap.md) + +--- + +## Dependensi lintas repo + +| Dependency | Owner | +|------------|-------| +| LDAP AD | `10.100.1.40` — geonet-console | +| OSS credential | `/opt/stacks/geonet-console/.env` | +| FE client | `mysupperapps_FE_PWA` | +| Push webhook | geonet-push (belum) | diff --git a/Zammad/docs/roadmap.md b/Zammad/docs/roadmap.md new file mode 100644 index 0000000..d107a8f --- /dev/null +++ b/Zammad/docs/roadmap.md @@ -0,0 +1,90 @@ +# Roadmap — Zammad (Super Apps) + +> **Terakhir Diperbarui:** 2026-07-03 + +Selaras dengan roadmap super apps di `backlog.md` (root workspace). + +--- + +## Fase ringkas + +| Fase | Isi | Status | +|------|-----|--------| +| **0** | Repo docs + OSS bucket | ✅ | +| **1** | Install Zammad + LDAP + nginx | ✅ | +| **1b** | SMTP notifikasi outbound | ✅ | +| **2** | FE `/ticketing` (mysupperapps_FE_PWA) | 🔄 **Berikutnya** | +| **3** | Mailcow + email channel inbound | 📋 | +| **4** | Webhook → push notification | 📋 | +| **5** | KPI / tiket metrics dashboard | 📋 | + +--- + +## Urutan disepakati + +| # | Item | Status | +|---|------|--------| +| 1 | OSS `zammad-attachments` | ✅ | +| 2 | Zammad install + nginx | ✅ | +| 3 | LDAP ke AD `10.100.1.40` | ✅ | +| 4 | Role mapping + uji login AD | 🔄 *(user)* | +| 5 | Group & kategori tiket | 📋 | +| 6 | API token | 📋 | +| **7** | **SMTP notifikasi** | ✅ | +| **8** | **FE `/ticketing`** | 🔄 **← sekarang** | +| **9** | **Mailcow** | 📋 | +| **10** | **Webhook → geonet-push** | 📋 | +| **11** | **KPI dashboard** | 📋 | + +--- + +## Fase 7 — SMTP notifikasi (detail) + +- [ ] Set `notification_sender` = `support@geonet.co.id` +- [ ] Channels → Email → SMTP `sc138.idcloudhosting.cloud:465` +- [ ] Test outbound OK +- [ ] Uji notifikasi tiket +- **Ref:** `docs/notes/smtp-notification-setup.md` +- **Script:** `scripts/test-smtp-connectivity.sh` + +--- + +## Fase 8 — FE `/ticketing` (detail) + +- [ ] API token `fe-ticketing-pwa` +- [ ] `zammad-client.ts` + env di mysupperapps_FE_PWA +- [ ] Halaman `/ticketing` — list, create, detail +- **Ref:** `docs/notes/fe-ticketing-integration.md`, `docs/api/overview.md` + +--- + +## Fase 9 — Mailcow + +- [ ] Install Mailcow +- [ ] Zammad email channel inbound `support@geonet.co.id` +- [ ] Migrasi SMTP dari idcloudhosting → Mailcow internal + +--- + +## Fase 10 — Webhook push + +- [ ] Zammad webhook → geonet-push service +- [ ] Notifikasi mobile untuk agent + +--- + +## Fase 11 — KPI dashboard + +- [ ] Metrics tiket (open, closed, SLA) +- [ ] Integrasi dashboard super apps + +--- + +## Catatan teknis + +| Keputusan | Detail | +|-----------|--------| +| SMTP host | `sc138.idcloudhosting.cloud:465` + SSL verify yes | +| SMTP sender | Wajib `@geonet.co.id` | +| LDAP UI | `System → Integrations` (`#system/integration/ldap`) | +| ES / PG | ES off; PG bundled 17 | diff --git a/Zammad/docs/security.md b/Zammad/docs/security.md new file mode 100644 index 0000000..d3aed85 --- /dev/null +++ b/Zammad/docs/security.md @@ -0,0 +1,51 @@ +# Security — Zammad + +> **Terakhir Diperbarui:** 2026-07-02 + +--- + +## Prinsip + +1. **Secret tidak masuk Git** — `.env`, token API, LDAP password, OSS secret hanya di server +2. **Bucket private** — `zammad-attachments` tanpa public ACL; akses via Zammad S3 credential saja +3. **HTTPS wajib** — UI/API publik lewat nginx + wildcard SSL `*.gisportal.id` +4. **LDAP bind** — gunakan service account dedicated jika memungkinkan (bukan Administrator produksi) +5. **API token FE** — scope minimal; rotasi jika bocor + +--- + +## Credential map + +| Secret | Lokasi | Jangan commit | +|--------|--------|---------------| +| Zammad `.env` | `/opt/stacks/zammad/.env` | ✅ | +| OSS keys (reuse) | `/opt/stacks/geonet-console/.env` | ✅ | +| PostgreSQL password | `.env` Zammad + backup vault | ✅ | +| Zammad API token (FE) | Zammad admin + FE `.env` terpisah | ✅ | + +--- + +## Network + +| Arah | Port | Catatan | +|------|------|---------| +| Internet → nginx → Zammad | 443 | Hanya reverse proxy | +| Zammad → PostgreSQL | 5432 | Internal LAN 10.100.1.25 | +| Zammad → LDAP | 389 | AD 10.100.1.40 | +| Zammad → OSS | 8010 | HTTP internal (bukan publik) | + +--- + +## Hardening (post-install) + +- [ ] Nonaktifkan signup publik (hanya LDAP) +- [ ] Rate limit nginx pada `/api/v1/` +- [ ] Backup DB terenkripsi + retention policy +- [ ] Audit log Zammad untuk perubahan role/group + +--- + +## Referensi + +- LDAP policy: [`server-connection/docs/adr/ADR-0003-ldap-authentication.md`](../../server-connection/docs/adr/ADR-0003-ldap-authentication.md) +- OSS: [`docs/adr/ADR-0002-oss-attachments-qnap.md`](adr/ADR-0002-oss-attachments-qnap.md) diff --git a/Zammad/docs/server.md b/Zammad/docs/server.md new file mode 100644 index 0000000..7da2c59 --- /dev/null +++ b/Zammad/docs/server.md @@ -0,0 +1,70 @@ +# Server — Zammad + +> **Terakhir Diperbarui:** 2026-07-02 + +--- + +## Host utama + +| Role | IP | Keterangan | +|------|-----|------------| +| **App + Docker + Nginx** | `10.100.1.24` | Zammad stack, reverse proxy | +| **PostgreSQL** | `10.100.1.25` | DB `zammad` (target) | +| **AD / LDAP** | `10.100.1.40` | Autentikasi user | +| **QNAP OSS** | `10.100.1.10:8010` | Bucket `zammad-attachments` | + +### SSH + +```bash +ssh -m hmac-sha1 root@10.100.1.24 -p 22 +ssh -m hmac-sha1 root@10.100.1.25 -p 22 +ssh -m hmac-sha1 Administrator@10.100.1.40 -p 22 +``` + +> Wajib **PowerShell** untuk key QNAP jika akses NAS langsung. + +--- + +## Server 10.100.1.24 — spesifikasi (2026-07-02) + +| Resource | Nilai | +|----------|-------| +| RAM | 62 GB | +| Disk `/` (cl-root) | 150 GB (~125 GB free) | +| Disk `/home` | 101 GB | +| `vm.max_map_count` | 262144 | +| Docker | 26.x | + +### Stack path (target) + +| Stack | Path | +|-------|------| +| Zammad | `/opt/stacks/zammad/` | +| geonet-console (OSS cred) | `/opt/stacks/geonet-console/` | + +### Nginx + +| File (target) | Domain | +|---------------|--------| +| `/etc/nginx/conf.d/production/zammad.conf` | `zammad.gisportal.id` | + +--- + +## Perintah umum + +```bash +# Status container Zammad (setelah install) +docker ps --filter name=zammad + +# Log +docker logs zammad-railsserver --tail 100 -f + +# Nginx test & reload +nginx -t && nginx -s reload +``` + +--- + +## Referensi lintas repo + +Detail server lengkap: [`server-connection/docs/server.md`](../../server-connection/docs/server.md) diff --git a/Zammad/docs/storage.md b/Zammad/docs/storage.md new file mode 100644 index 0000000..7f1f4c4 --- /dev/null +++ b/Zammad/docs/storage.md @@ -0,0 +1,71 @@ +# Storage — Zammad Attachments (QNAP OSS) + +> **Terakhir Diperbarui:** 2026-07-02 + +--- + +## Ringkasan + +| Item | Nilai | +|------|-------| +| Provider | QNAP QuObjects (S3-compatible) | +| Endpoint | `http://10.100.1.10:8010` | +| Bucket | **`zammad-attachments`** | +| ACL | **Private** (tidak public-read) | +| Credential | Reuse `super-apps:` dari geonet-console | +| Zammad storage mode | Simple Storage (S3) | + +--- + +## Status bucket (2026-07-02) + +- ✅ Bucket dibuat +- ✅ Upload/download test berhasil (`_healthcheck/oss-setup-test.txt`) +- ⚠️ Upload pertama setelah create bisa `503` — retry setelah beberapa detik (normal QuObjects) + +--- + +## Verifikasi bucket + +Jalankan dari server `10.100.1.24`: + +```bash +export $(grep -E "^OSS_" /opt/stacks/geonet-console/.env | xargs) +export OSS_BUCKET_TARGET=zammad-attachments +docker cp /opt/stacks/zammad/scripts/oss-create-bucket.php geonet-console:/tmp/oss-create-bucket.php +# atau dari repo: Zammad/scripts/oss-create-bucket.php +docker exec \ + -e OSS_ACCESS_KEY_ID="$OSS_ACCESS_KEY_ID" \ + -e OSS_SECRET_ACCESS_KEY="$OSS_SECRET_ACCESS_KEY" \ + -e OSS_ENDPOINT="$OSS_ENDPOINT" \ + -e OSS_REGION="$OSS_REGION" \ + -e OSS_BUCKET_TARGET="$OSS_BUCKET_TARGET" \ + geonet-console php /tmp/oss-create-bucket.php +``` + +Script membutuhkan AWS SDK PHP (tersedia di container `geonet-console`). + +--- + +## Zammad UI + +Setelah `storage.yml` / env dikonfigurasi dan Zammad di-restart: + +**Settings → System → Storage → Simple Storage (S3) → Submit** + +--- + +## Perbedaan dengan bucket `super-apps` + +| | `super-apps` | `zammad-attachments` | +|---|--------------|----------------------| +| Use case | Avatar FE (public URL) | Tiket attachment (private) | +| Nginx public proxy | ✅ `file.gisportal.id/super-apps/` | ❌ Tidak perlu | +| ACL | public-read | private | + +--- + +## Referensi + +- ADR: [`docs/adr/ADR-0002-oss-attachments-qnap.md`](adr/ADR-0002-oss-attachments-qnap.md) +- OSS umum: [`server-connection/docs/adr/ADR-0004-qnap-object-storage.md`](../../server-connection/docs/adr/ADR-0004-qnap-object-storage.md) diff --git a/Zammad/docs/system-requirements.md b/Zammad/docs/system-requirements.md new file mode 100644 index 0000000..c45b93d --- /dev/null +++ b/Zammad/docs/system-requirements.md @@ -0,0 +1,28 @@ +# System Requirements — Zammad + +| Field | Value | +|-------|-------| +| Project | `Zammad/` | +| Tipe | infra (helpdesk) | +| Last updated | 2026-07-06 | + +## Runtime + +| Tool | Versi | +|------|-------| +| Zammad | 7.1.1-0012 | +| Docker Compose | v2 | +| PostgreSQL | 17 (bundled) | +| Elasticsearch | disabled | +| nginx | 1.27 (host `.24`) | + +## Dependency + +| Service | Host | +|---------|------| +| Reverse proxy | `10.100.1.24` | +| LDAP | `10.100.1.40` | +| OSS | `file.gisportal.id` (QNAP) | +| Mailcow (planned) | `10.100.1.28` | + +Env: [.env.example](../.env.example), [environment.md](./environment.md). diff --git a/Zammad/docs/todo.md b/Zammad/docs/todo.md new file mode 100644 index 0000000..893d235 --- /dev/null +++ b/Zammad/docs/todo.md @@ -0,0 +1,62 @@ +# TODO — Zammad + +> **Terakhir Diperbarui:** 2026-07-03 + +--- + +## ✅ Selesai — Fase 7: SMTP notifikasi (2026-07-03) + +- Outbound SMTP aktif: `sc138.idcloudhosting.cloud:465` SSL +- User: `support@geonet.co.id` · sender: `"Geonet Support" ` +- Fix DNS container Docker (`docker-compose.override.yml`) +- **Opsional:** buat tiket uji → verifikasi email notifikasi terkirim + +--- + +## 🔴 High Priority — Fase 8: FE `/ticketing` + +### API token untuk mysupperapps_FE_PWA — ✅ 2026-07-03 +- **Name:** `fe-ticketing-pwa` +- **Server:** `/opt/stacks/zammad/.fe-ticketing-token` +- **Ref:** `docs/notes/fe-ticketing-integration.md` + +### Implementasi FE (repo terpisah) +- **Repo:** `mysupperapps_FE_PWA` +- **File:** `src/lib/zammad-client.ts`, route `/ticketing` +- **Estimasi:** 1–2 hari + +--- + +## 🟡 Medium Priority — Polish Fase 1 + +### Role mapping AD (jika belum) +- **Ref:** `docs/notes/ldap-ad-setup.md` langkah 4 + +### Investigasi 3 user LDAP gagal sync +- **Tindakan:** Cek `mail` di AD, sync ulang + +### Verifikasi S3 storage upload +- **Lokasi:** `Settings → System → Storage` + +--- + +## 🟢 Low Priority — Fase 9+ + +| Fase | Item | +|------|------| +| 9 | Mailcow install + Zammad email channel inbound | +| 10 | Webhook Zammad → geonet-push | +| 11 | KPI / metrics dashboard | +| — | Migrasi PG ke `.25` (butuh PG 13+) | +| — | Elasticsearch (butuh CPU upgrade) | + +--- + +## ✅ Selesai + +| Item | Tanggal | +|------|---------| +| Deploy Zammad + nginx + OSS | 2026-07-02 | +| LDAP AD `GIS Portal AD` | 2026-07-02 | +| Panduan SMTP + FE integration docs | 2026-07-03 | +| Script `scripts/test-smtp-connectivity.sh` | 2026-07-03 | diff --git a/Zammad/docs/troubleshooting.md b/Zammad/docs/troubleshooting.md new file mode 100644 index 0000000..e30dd8c --- /dev/null +++ b/Zammad/docs/troubleshooting.md @@ -0,0 +1,73 @@ +# Troubleshooting — Zammad + +> **Terakhir Diperbarui:** 2026-07-02 + +--- + +## OSS / S3 + +### Upload attachment gagal di Zammad + +1. Cek `storage.yml` / env S3 di container Zammad +2. Verifikasi bucket dari server: + +```bash +export $(grep -E "^OSS_" /opt/stacks/geonet-console/.env | xargs) +export OSS_BUCKET_TARGET=zammad-attachments +docker exec -e OSS_ACCESS_KEY_ID -e OSS_SECRET_ACCESS_KEY -e OSS_ENDPOINT -e OSS_REGION -e OSS_BUCKET_TARGET \ + geonet-console php /tmp/oss-create-bucket.php +``` + +3. Pastikan `force_path_style: true` dan endpoint `http://10.100.1.10:8010` + +### 503 saat create bucket / upload pertama + +Lihat [`issues.md`](issues.md) — retry setelah beberapa detik. + +--- + +## Elasticsearch + +### Zammad lambat atau search error + +```bash +docker logs zammad-elasticsearch --tail 50 +``` + +- Pastikan `vm.max_map_count=262144` di host (`sysctl vm.max_map_count`) +- Cek RAM tersedia (target stack ~8–12 GB dengan ES) + +--- + +## LDAP + +### User LDAP tidak bisa login + +1. Test bind dari server .24 ke `10.100.1.40:389` +2. Cek Base DN: `DC=gisportal,DC=id` +3. Pastikan filter user/group di Zammad sesuai atribut AD +4. Bandingkan dengan config geonet-console (`server-connection/docs/environment.md`) + +--- + +## Nginx + +### 502 Bad Gateway + +```bash +docker ps --filter name=zammad +curl -sI http://127.0.0.1:/ +nginx -t +``` + +Pastikan upstream mengarah ke container `zammad-railsserver` yang healthy. + +--- + +## PostgreSQL eksternal + +### Connection refused ke 10.100.1.25 + +- Cek `pg_hba.conf` mengizinkan host `10.100.1.24` +- Cek firewall internal +- Verifikasi user `zammad` dan database `zammad` ada diff --git a/Zammad/docs/version.md b/Zammad/docs/version.md new file mode 100644 index 0000000..7916a34 --- /dev/null +++ b/Zammad/docs/version.md @@ -0,0 +1,28 @@ +# Version History — Zammad + +--- + +## [7.1.1-0012.1] - 2026-07-06 + +- Bootstrap AI-Agent-Standards (AGENTS.md, version.md, guide/, system-requirements.md) +- Docs Mailcow channel prep (belum cutover SMTP/IMAP) + +--- + +## [7.1.1-0012] - 2026-07-03 + +- SMTP notifikasi `support@geonet.co.id` via cPanel SSL 465 +- Feedback sync dari geonet-console + +--- + +## [7.1.1-0012] - 2026-07-02 + +- Deploy Zammad + nginx + LDAP AD + OSS bucket +- API token FE `fe-ticketing-pwa` + +--- + +## [0.1.0] - 2026-07-01 + +- Inisialisasi dokumentasi repo diff --git a/Zammad/infra/README.md b/Zammad/infra/README.md new file mode 100644 index 0000000..8247cd4 --- /dev/null +++ b/Zammad/infra/README.md @@ -0,0 +1,11 @@ +# Infra — Zammad + +Artefak deploy untuk stack Zammad di `10.100.1.24`. + +| Path | Keterangan | +|------|------------| +| `infra/nginx/zammad.gisportal.id.conf` | Nginx vhost (deploy ke `/etc/nginx/conf.d/production/`) | +| `infra/zammad/storage.yml.example` | Template S3 storage — salin ke volume Zammad di server | +| `scripts/oss-create-bucket.php` | Verifikasi / buat bucket `zammad-attachments` | + +Stack runtime (`docker-compose`) di-clone dari upstream [zammad-docker-compose](https://github.com/zammad/zammad-docker-compose) ke `/opt/stacks/zammad/` — tidak di-vendor di repo ini. diff --git a/Zammad/infra/nginx/zammad.gisportal.id.conf b/Zammad/infra/nginx/zammad.gisportal.id.conf new file mode 100644 index 0000000..d239561 --- /dev/null +++ b/Zammad/infra/nginx/zammad.gisportal.id.conf @@ -0,0 +1,78 @@ +# zammad.gisportal.id → Zammad (Docker) +# Deploy: /etc/nginx/conf.d/production/zammad.conf on 10.100.1.24 +# +# NOTE: Adjust upstream port after docker compose up (default zammad-docker-compose exposes 8080) + +upstream zammad_backend { + server 127.0.0.1:8093; + keepalive 8; +} + +limit_req_zone $binary_remote_addr zone=zammad_general:10m rate=30r/s; + +server { + listen 80; + server_name zammad.gisportal.id; + return 301 https://zammad.gisportal.id$request_uri; +} + +server { + listen 443 ssl; + server_name zammad.gisportal.id; + include /etc/nginx/conf.d/ssl.conf; + + add_header X-Frame-Options "SAMEORIGIN" always; + add_header X-Content-Type-Options "nosniff" always; + add_header Referrer-Policy "strict-origin-when-cross-origin" always; + add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; + + client_max_body_size 50m; + + # CORS for FE PWA my.gisportal.id — /api/ only (adjust after token flow defined) + location /api/ { + if ($http_origin = "https://my.gisportal.id") { + add_header Access-Control-Allow-Origin "https://my.gisportal.id" always; + add_header Access-Control-Allow-Methods "GET, POST, PUT, PATCH, DELETE, OPTIONS" always; + add_header Access-Control-Allow-Headers "Authorization, Content-Type, X-Requested-With" always; + add_header Access-Control-Max-Age 3600 always; + } + + if ($request_method = OPTIONS) { + add_header Access-Control-Allow-Origin "https://my.gisportal.id" always; + add_header Access-Control-Allow-Methods "GET, POST, PUT, PATCH, DELETE, OPTIONS" always; + add_header Access-Control-Allow-Headers "Authorization, Content-Type, X-Requested-With" always; + add_header Access-Control-Max-Age 3600 always; + add_header Content-Length 0; + add_header Content-Type text/plain; + return 204; + } + + limit_req zone=zammad_general burst=50 nodelay; + + proxy_pass http://zammad_backend; + proxy_http_version 1.1; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_set_header X-Forwarded-Host $host; + proxy_read_timeout 120s; + } + + location / { + limit_req zone=zammad_general burst=50 nodelay; + + proxy_pass http://zammad_backend; + proxy_http_version 1.1; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_set_header X-Forwarded-Host $host; + proxy_read_timeout 120s; + + # WebSocket (Zammad live updates) + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + } +} diff --git a/Zammad/infra/zammad/docker-compose.override.yml b/Zammad/infra/zammad/docker-compose.override.yml new file mode 100644 index 0000000..010c311 --- /dev/null +++ b/Zammad/infra/zammad/docker-compose.override.yml @@ -0,0 +1,47 @@ +# Deployed on 10.100.1.24 — copy to /opt/stacks/zammad/docker-compose.override.yml +# DNS: Docker embedded resolver (127.0.0.11) gagal resolve external host — wajib untuk SMTP. +services: + zammad-elasticsearch: + profiles: + - do-not-start + zammad-railsserver: + dns: + - 203.142.82.222 + - 203.142.84.222 + depends_on: + zammad-init: + condition: service_completed_successfully + zammad-memcached: + condition: service_healthy + zammad-postgresql: + condition: service_healthy + zammad-redis: + condition: service_healthy + volumes: + - zammad-backup:/var/tmp/zammad:ro + - zammad-storage:/opt/zammad/storage + - ./config/storage.yml:/opt/zammad/config/storage.yml:ro + zammad-scheduler: + dns: + - 203.142.82.222 + - 203.142.84.222 + volumes: + - zammad-backup:/var/tmp/zammad:ro + - zammad-storage:/opt/zammad/storage + - ./config/storage.yml:/opt/zammad/config/storage.yml:ro + zammad-websocket: + dns: + - 203.142.82.222 + - 203.142.84.222 + volumes: + - zammad-backup:/var/tmp/zammad:ro + - zammad-storage:/opt/zammad/storage + - ./config/storage.yml:/opt/zammad/config/storage.yml:ro + zammad-nginx: + dns: + - 203.142.82.222 + - 203.142.84.222 + volumes: + - zammad-backup:/var/tmp/zammad:ro + - zammad-storage:/opt/zammad/storage + - ./config/storage.yml:/opt/zammad/config/storage.yml:ro diff --git a/Zammad/infra/zammad/storage.yml.example b/Zammad/infra/zammad/storage.yml.example new file mode 100644 index 0000000..40510ca --- /dev/null +++ b/Zammad/infra/zammad/storage.yml.example @@ -0,0 +1,12 @@ +# Copy to Zammad storage config volume on server. +# Fill secret_access_key from /opt/stacks/geonet-console/.env — DO NOT commit real values. + +s3: + access_key_id: 'super-apps:' + secret_access_key: '' + region: 'us-east-1' + endpoint: 'http://10.100.1.10:8010' + bucket: 'zammad-attachments' + force_path_style: true + request_checksum_calculation: when_required + response_checksum_validation: when_required diff --git a/Zammad/perintah.md b/Zammad/perintah.md new file mode 100644 index 0000000..ee7e370 --- /dev/null +++ b/Zammad/perintah.md @@ -0,0 +1,32 @@ +# Protokol Sync — Zammad + +> Wajib di akhir sesi. Repository = sumber kebenaran; percakapan bukan dokumentasi. + +## Indeks cepat + +| Topik | File | +|-------|------| +| Entry point AI | `docs/context-index.md` | +| Status & fase | `docs/project-status.md` | +| Next actions | `docs/todo.md` | +| Deploy | `docs/deployment.md` | +| OSS attachments | `docs/storage.md` | +| Server & SSH | `docs/server.md` | + +## Checklist sebelum nyatakan selesai + +- [ ] `docs/project-status.md` diperbarui +- [ ] `docs/todo.md` diperbarui +- [ ] `docs/changelog.md` untuk perubahan penting +- [ ] ADR baru jika ada keputusan arsitektur +- [ ] `docs/context-index.md` jika ada dokumen baru +- [ ] Tidak ada secret di commit + +### Sync terakhir: 2026-07-02 + +- Repo `Zammad/` dibuat di monorepo LDAPWeb +- Bucket OSS `zammad-attachments` siap (QNAP, credential reuse `super-apps`) +- **Zammad installed** — `https://zammad.gisportal.id`, stack `/opt/stacks/zammad/` +- PostgreSQL: bundled PG 17 (bukan `.25` — PG 12 incompatible) +- Elasticsearch: **disabled** (CPU x86-64-v2); S3 storage configured +- Berikutnya: setup wizard admin, LDAP AD, API token untuk FE diff --git a/Zammad/scripts/install-zammad-server.sh b/Zammad/scripts/install-zammad-server.sh new file mode 100644 index 0000000..fdf0490 --- /dev/null +++ b/Zammad/scripts/install-zammad-server.sh @@ -0,0 +1,65 @@ +#!/bin/bash +# Run on 10.100.1.24 as root — installs Zammad docker stack. +# Prerequisites: geonet-console .env with OSS keys, nginx ssl.conf, DNS zammad.gisportal.id +set -euo pipefail +STACK=/opt/stacks/zammad +mkdir -p "$STACK/config" +cd "$STACK" + +if [ ! -f docker-compose.yml ]; then + git clone https://github.com/zammad/zammad-docker-compose.git /tmp/zammad-clone + cp -a /tmp/zammad-clone/. "$STACK/" + rm -rf /tmp/zammad-clone +fi + +# Bind internal nginx to localhost only (port 8080 is used by host nginx/jira) +python3 - <<'PY' +from pathlib import Path +p = Path('docker-compose.yml') +text = p.read_text() +text = text.replace( + ' - "${NGINX_EXPOSE_PORT:-8080}:${NGINX_PORT:-8080}"', + ' - "127.0.0.1:8093:${NGINX_PORT:-8080}"', +) +p.write_text(text) +PY + +source /opt/stacks/geonet-console/.env + +cat > .env < config/storage.yml </dev/null || true + +docker compose pull +docker compose up -d +echo "Zammad stack started. Verify: curl -sI http://127.0.0.1:8093/" diff --git a/Zammad/scripts/oss-create-bucket.php b/Zammad/scripts/oss-create-bucket.php new file mode 100644 index 0000000..83f061f --- /dev/null +++ b/Zammad/scripts/oss-create-bucket.php @@ -0,0 +1,80 @@ + 'latest', + 'region' => $region, + 'endpoint' => $endpoint, + 'use_path_style_endpoint' => true, + 'credentials' => [ + 'key' => $key, + 'secret' => $secret, + ], +]); + +echo "=== List buckets ===\n"; +foreach ($client->listBuckets()['Buckets'] ?? [] as $b) { + echo ' - ' . $b['Name'] . "\n"; +} + +if (!$client->doesBucketExist($bucket)) { + echo "Creating bucket: {$bucket}\n"; + $client->createBucket(['Bucket' => $bucket]); + echo "Created.\n"; +} else { + echo "Bucket already exists: {$bucket}\n"; +} + +$testKey = '_healthcheck/oss-setup-test.txt'; +$body = 'zammad-oss-test-' . gmdate('c'); + +$lastError = null; +for ($attempt = 1; $attempt <= 5; $attempt++) { + try { + $client->putObject([ + 'Bucket' => $bucket, + 'Key' => $testKey, + 'Body' => $body, + 'ContentType' => 'text/plain', + ]); + echo "Upload OK (attempt {$attempt}): {$testKey}\n"; + $lastError = null; + break; + } catch (Throwable $e) { + $lastError = $e; + echo "Upload attempt {$attempt} failed: " . $e->getMessage() . "\n"; + sleep(3); + } +} + +if ($lastError !== null) { + fwrite(STDERR, "Upload failed after retries. Bucket exists but write test did not pass.\n"); + exit(2); +} + +$got = (string) $client->getObject(['Bucket' => $bucket, 'Key' => $testKey])['Body']; +if ($got !== $body) { + fwrite(STDERR, "Download mismatch\n"); + exit(1); +} +echo "Download OK\n"; +echo "DONE: bucket {$bucket} ready (private — no public ACL set)\n"; diff --git a/Zammad/scripts/setup-postgres-zammad.sh b/Zammad/scripts/setup-postgres-zammad.sh new file mode 100644 index 0000000..0165213 --- /dev/null +++ b/Zammad/scripts/setup-postgres-zammad.sh @@ -0,0 +1,23 @@ +#!/bin/bash +set -euo pipefail +ZAMMAD_DB_PASS=$(openssl rand -hex 16) +export ZAMMAD_DB_PASS + +sudo -u postgres psql <&1; then + echo "OK: $host:$port" + else + echo "FAIL: $host:$port" + fi + done +done + +echo "" +echo "=== SSL certificate (sc138:465) ===" +echo | openssl s_client -connect sc138.idcloudhosting.cloud:465 \ + -servername sc138.idcloudhosting.cloud 2>/dev/null \ + | openssl x509 -noout -subject -issuer 2>/dev/null || true + +echo "" +echo "=== Zammad Email::Notification channels ===" +if docker ps --format '{{.Names}}' | grep -q zammad-zammad-railsserver; then + docker exec zammad-zammad-railsserver-1 bundle exec rails runner \ + "Channel.where(area: 'Email::Notification').each { |c| puts \"id=#{c.id} active=#{c.active} adapter=#{c.options.dig(:outbound,:adapter)} status=#{c.status_out}\" }" \ + 2>/dev/null | grep -vE 'INFO|WARN|ActionCable|memcached|Redis|Dalli' || true +else + echo "Zammad railsserver container not running on this host" +fi diff --git a/nginx/.env.example b/nginx/.env.example new file mode 100644 index 0000000..be80202 --- /dev/null +++ b/nginx/.env.example @@ -0,0 +1,6 @@ +# nginx infra — .env.example +NGINX_HOST=10.100.1.24 +NGINX_SSH_ALIAS=reverse-proxy +SSL_WILDCARD_GISPORTAL=/home/ssl-gisportal/gisportal.id-fullchain.pem +SSL_GEONET=/etc/nginx/sslgeonet.co.id/ +STACKS_PATH=/opt/stacks/ diff --git a/nginx/AGENTS.md b/nginx/AGENTS.md new file mode 100644 index 0000000..5e32f9a --- /dev/null +++ b/nginx/AGENTS.md @@ -0,0 +1,33 @@ +# AGENTS.md — Cold Start + +> Project: nginx/ +> Sesi: [docs/ai-session-summary.md](./docs/ai-session-summary.md) +> Peta: [docs/context-index.md](./docs/context-index.md) + +## Apa ini? + +Reverse proxy nginx di 10.100.1.24 — TLS termination, vhost *.gisportal.id + +## Aturan kritis + +- Config live di server — repo = template + dokumentasi +- No hardcoded domain di app — vhost di /etc/nginx/conf.d/ +- Reload: nginx -t && nginx -s reload +- Deploy vhost baru → append docs/version.md +- **No hardcoded URL** — .env.example + +- No commit kecuali user minta +- Pengetahuan penting wajib ke docs + +## Lanjut kerja + +1. AGENTS.md → docs/ai-session-summary.md → STOP +2. docs/server.md, docs/todo.md + +## Pointer + +| Butuh | Buka | +|-------|------| +| Versi | [docs/version.md](./docs/version.md) | +| Server | [docs/server.md](./docs/server.md) | +| Migrasi | [docs/guide/migration.md](./docs/guide/migration.md) | diff --git a/nginx/docs/adr/000-template.md b/nginx/docs/adr/000-template.md new file mode 100644 index 0000000..e729785 --- /dev/null +++ b/nginx/docs/adr/000-template.md @@ -0,0 +1,3 @@ +# ADR template + +Salin untuk keputusan arsitektur baru. diff --git a/nginx/docs/ai-session-summary.md b/nginx/docs/ai-session-summary.md new file mode 100644 index 0000000..baec349 --- /dev/null +++ b/nginx/docs/ai-session-summary.md @@ -0,0 +1,14 @@ +# AI Session Summary + +`yaml +session: 2026-07-06-init +project: nginx/ +version: 1.0.0 +status: ready +next: Lengkapi operasional dari server live +` + +## TL;DR + +- Bootstrap docs AI-Agent-Standards untuk infra nginx +- Host utama: 10.100.1.24 (proxy.lan) diff --git a/nginx/docs/changelog.md b/nginx/docs/changelog.md new file mode 100644 index 0000000..54fd704 --- /dev/null +++ b/nginx/docs/changelog.md @@ -0,0 +1,6 @@ +# Changelog — nginx + +## [1.0.0] - 2026-07-06 + +### Added +- Struktur dokumentasi AI-Agent-Standards diff --git a/nginx/docs/context-index.md b/nginx/docs/context-index.md new file mode 100644 index 0000000..23b38ad --- /dev/null +++ b/nginx/docs/context-index.md @@ -0,0 +1,20 @@ +# Context Index — nginx + +## Zona A + +| Item | Value | +|------|-------| +| Path | nginx/ | +| Cold start | [../AGENTS.md](../AGENTS.md) | +| Versi | 1.0.0 — [version.md](./version.md) | +| Stack | nginx 1.27, certbot, conf.d/ | +| Tipe | infra | +| Last updated | 2026-07-06 | + +## Zona B + +| Dokumen | Path | +|---------|------| +| Server | [server.md](./server.md) | +| Todo | [todo.md](./todo.md) | +| Migrasi | [guide/migration.md](./guide/migration.md) | diff --git a/nginx/docs/guide/README.md b/nginx/docs/guide/README.md new file mode 100644 index 0000000..e724bbb --- /dev/null +++ b/nginx/docs/guide/README.md @@ -0,0 +1,3 @@ +# Guides + +- [migration.md](./migration.md) diff --git a/nginx/docs/guide/migration.md b/nginx/docs/guide/migration.md new file mode 100644 index 0000000..8de25b7 --- /dev/null +++ b/nginx/docs/guide/migration.md @@ -0,0 +1,16 @@ +# Migration Guide + +## Host + +| Item | Nilai | +|------|-------| +| IP | 10.100.1.24 | +| SSH | ssh reverse-proxy | +| Config | /etc/nginx/conf.d/ | + +## Tambah vhost baru + +1. Salin template dari repo app (infra/nginx/) +2. Deploy ke /etc/nginx/conf.d/production/ +3. nginx -t && nginx -s reload +4. Append version.md diff --git a/nginx/docs/issues.md b/nginx/docs/issues.md new file mode 100644 index 0000000..8a107e9 --- /dev/null +++ b/nginx/docs/issues.md @@ -0,0 +1,3 @@ +# Issues + +Belum ada issue terdokumentasi. diff --git a/nginx/docs/project-status.md b/nginx/docs/project-status.md new file mode 100644 index 0000000..5d55a20 --- /dev/null +++ b/nginx/docs/project-status.md @@ -0,0 +1,8 @@ +# Project Status — nginx + +Reverse proxy nginx di 10.100.1.24 — TLS termination, vhost *.gisportal.id + +| Item | Status | +|------|--------| +| Dokumentasi bootstrap | Done 2026-07-06 | +| Operasional | Lihat server.md | diff --git a/nginx/docs/server.md b/nginx/docs/server.md new file mode 100644 index 0000000..8040f52 --- /dev/null +++ b/nginx/docs/server.md @@ -0,0 +1,93 @@ +# Server — nginx + +> **Last updated:** 2026-07-06 +> Config live di server — verifikasi via SSH sebelum mengandalkan docs. + +| Item | Nilai | +|------|-------| +| Host | `proxy.lan` / `10.100.1.24` | +| SSH | `ssh reverse-proxy` | +| nginx | 1.27 | +| SSL wildcard | `/home/ssl-gisportal/gisportal.id-fullchain.pem` | +| SSL geonet | `/etc/nginx/sslgeonet.co.id/` | +| Docker stacks | `/opt/stacks/` (Dockge) | + +--- + +## Struktur config + +``` +/etc/nginx/nginx.conf + include conf.d/*.conf + include conf.d/production/*.conf + include conf.d/development/*.conf +``` + +| Path | Fungsi | +|------|--------| +| `conf.d/ssl.conf` | SSL global | +| `conf.d/default-wildcard.conf` | catch-all → redirect support-portal | +| `conf.d/production/` | vhost produksi | +| `conf.d/development/` | vhost dev | +| `conf.d/nonaktif/` | tidak diload | + +Reload: `nginx -t && nginx -s reload` + +--- + +## DNS (split-DNS MikroTik `10.100.1.1`) + +| Pattern | Target | Catatan | +|---------|--------|---------| +| `^dev\.gisportal\.id` | `10.100.1.51` | bypass reverse-proxy | +| `\.gisportal\.id` | `10.100.1.24` | catch-all | +| `iguf.geonet.co.id` | `10.100.1.24` | `geonet.iguf.conf` | + +**DNS publik:** + +| Domain | IP publik | NAT → | +|--------|-----------|-------| +| `dev.gisportal.id` | `117.102.73.100` | `10.100.1.51:443` | +| `*.gisportal.id` | `117.102.73.102` | `10.100.1.24:443` | +| `iguf.geonet.co.id` | `117.102.73.99` | `10.100.1.24:443` | +| `sync.geonet.co.id` | `117.102.73.102` | `10.100.1.24:443` → `10.100.1.28` | + +--- + +## Domain kunci + +| Domain | Backend | +|--------|---------| +| `console.gisportal.id` | geonet-console Docker | +| `my.gisportal.id` | mysupperapps FE | +| `zammad.gisportal.id` | `127.0.0.1:8093` | +| `sync.geonet.co.id` | `https://10.100.1.28:443` | +| `agent.gisportal.id` | GeoNetAgent collector | +| `file.gisportal.id` | QNAP `10.100.1.10` | +| `git.gisportal.id` | Gitea `10.100.1.41:3000` | +| `dockge.gisportal.id` | Dockge UI | + +Template vhost di repo app: `Mailcow/infra/nginx/`, `Zammad/infra/nginx/`, `GeoNetAgent/infra/nginx/`. + +--- + +## SSL / HTTP2 + +Cipher lemah (RC4, SSLv3) → `ERR_HTTP2_INADEQUATE_TRANSPORT_SECURITY`. + +```nginx +ssl_protocols TLSv1.2 TLSv1.3; +ssl_prefer_server_ciphers off; +``` + +--- + +## Mapping ke monorepo + +| Repo | Config template | +|------|-----------------| +| Mailcow | `Mailcow/infra/nginx/sync.geonet.co.id.conf` | +| Zammad | `Zammad/infra/nginx/zammad.gisportal.id.conf` | +| GeoNetAgent | `GeoNetAgent/infra/nginx/` | + +**Deprecated:** `server-audit/.cursor/infra-reverse-proxy.md` → gunakan file ini. diff --git a/nginx/docs/system-requirements.md b/nginx/docs/system-requirements.md new file mode 100644 index 0000000..076009d --- /dev/null +++ b/nginx/docs/system-requirements.md @@ -0,0 +1,8 @@ +# System Requirements — nginx + +| Field | Value | +|-------|-------| +| Stack | nginx 1.27, certbot, conf.d/ | +| Host | 10.100.1.24 | + +Env: [../.env.example](../.env.example) diff --git a/nginx/docs/todo.md b/nginx/docs/todo.md new file mode 100644 index 0000000..199332d --- /dev/null +++ b/nginx/docs/todo.md @@ -0,0 +1,9 @@ +# TODO — nginx + +## High + +- [ ] Verifikasi config live vs dokumentasi repo + +## Selesai + +- [x] Bootstrap AI-Agent-Standards 2026-07-06 diff --git a/nginx/docs/version.md b/nginx/docs/version.md new file mode 100644 index 0000000..b0a0961 --- /dev/null +++ b/nginx/docs/version.md @@ -0,0 +1,7 @@ +# Version History + +## [1.0.0] - 2026-07-06 + +- Bootstrap dokumentasi AI-Agent-Standards +- Indeks vhost dari server-audit infra-reverse-proxy +- Template vhost tersebar: Mailcow/, Zammad/, GeoNetAgent/, server-connection/ diff --git a/server-audit/.cursor/infra-reverse-proxy.md b/server-audit/.cursor/infra-reverse-proxy.md index 813f16a..6f25782 100644 --- a/server-audit/.cursor/infra-reverse-proxy.md +++ b/server-audit/.cursor/infra-reverse-proxy.md @@ -1,5 +1,8 @@ # Reverse Proxy — nginx (10.100.1.24 / proxy.lan) +> **Deprecated** — SSOT pindah ke [`nginx/docs/server.md`](../../nginx/docs/server.md). +> File ini dipertahankan sebagai redirect; jangan update di sini. + Dokumentasi infrastruktur reverse-proxy untuk AI Agent. **Bukan** sumber kebenaran config live — selalu verifikasi di server. ## Peran server diff --git a/server-audit/deploy-log.md b/server-audit/deploy-log.md index 6445997..f54b16f 100644 --- a/server-audit/deploy-log.md +++ b/server-audit/deploy-log.md @@ -2,7 +2,20 @@ --- -## 2026-07-01 — Feature Feedback Super Apps +## 2026-07-03 — Feedback → Zammad ticket sync + +### Backend (geonet-console) +- `ZammadTicketService` — auto-create tiket setelah `POST /api/v1/feedback` +- Migration `zammad_ticket_id`, `zammad_ticket_number`, `zammad_synced_at`, `zammad_sync_error` +- Env: `ZAMMAD_*` di `.env` + token dari `/opt/stacks/zammad/.fe-ticketing-token` +- Fix DNS Docker di `compose.yaml` (sama issue seperti stack Zammad) +- Deploy: `docker cp` + `compose up -d` — **verified** feedback #5 → Zammad ticket **#40002** + +### FE (my.gisportal.id) — belum di-update di repo ini +- Response API sekarang include `zammad_ticket_number`, `zammad_ticket_url` +- Lihat `docapi/services/feedback/store.md` + +--- ### Frontend (my.gisportal.id) - Buat `src/components/feedback/feedback-dialog.tsx` — dialog form laporan bug/saran diff --git a/server-audit/host.md b/server-audit/host.md index 6397daf..e00a7dd 100644 --- a/server-audit/host.md +++ b/server-audit/host.md @@ -1,3 +1,13 @@ +# Workstation MULTIMEDIA (Windows 10 Pro): + ssh multimedia + ssh admin@10.100.1.14 -p 22 + ssh admin@192.168.0.18 -p 22 + # Hostname: MULTIMEDIA | Dual NIC: 10.100.1.14 (utama, LAN server) + 192.168.0.18 (LAN MikroTik) + # Dokumentasi lengkap: PC-Multimedia/docs/server.md + # Key setup (jalankan sekali di PC MULTIMEDIA, PowerShell Admin): + # .\server-audit\scripts\setup-ssh-key-multimedia.ps1 + # Key laptop: ~/.ssh/id_ed25519_geonet_proxmox → C:\ProgramData\ssh\administrators_authorized_keys + # Mikrotik : ssh -m hmac-sha1 admin@10.100.1.1 -p 255 ssh -i "$env:USERPROFILE\.ssh\id_rsa_mikrotik" -o IdentitiesOnly=yes -m hmac-sha1 -p 255 admin@10.100.1.1 @@ -48,6 +58,11 @@ ssh -i "$env:USERPROFILE\.ssh\id_rsa_mikrotik" -o IdentitiesOnly=yes -m hmac-sha - Status: ✅ Resource tersedia, siap deploy - Integrasi: feedback dari Super Apps → auto-create tiket Zammad +# Mailserver (Mailcow): + ssh mailcow + ssh root@10.100.1.28 + # Key: ~/.ssh/id_ed25519_mailcow — passwordless OK 2026-07-03 + # Main_Database: ssh -m hmac-sha1 root@10.100.1.25 -p 22 diff --git a/server-audit/scripts/setup-ssh-key-multimedia.ps1 b/server-audit/scripts/setup-ssh-key-multimedia.ps1 new file mode 100644 index 0000000..93510a9 --- /dev/null +++ b/server-audit/scripts/setup-ssh-key-multimedia.ps1 @@ -0,0 +1,43 @@ +# Jalankan di MULTIMEDIA sebagai Administrator (PowerShell Admin) +# Tujuan: passwordless SSH dari laptop dev (key id_ed25519_geonet_proxmox) + +$ErrorActionPreference = 'Stop' + +$pubKey = 'ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDxlXfuXAb/A2YCji3XWckW37Hs7SP/yen2CQwgV5M4x proxmox-geonet' +$authFile = 'C:\ProgramData\ssh\administrators_authorized_keys' +$sshDir = 'C:\ProgramData\ssh' + +if (-not (Test-Path $sshDir)) { + New-Item -ItemType Directory -Path $sshDir | Out-Null +} + +$existing = '' +if (Test-Path $authFile) { + $existing = Get-Content $authFile -Raw -ErrorAction SilentlyContinue +} + +if ($existing -and $existing.Contains('AAAAC3NzaC1lZDI1NTE5AAAAIDxlXfuXAb/A2YCji3XWckW37Hs7SP/yen2CQwgV5M4x')) { + Write-Host 'Public key sudah ada di administrators_authorized_keys' +} else { + Add-Content -Path $authFile -Value $pubKey + Write-Host 'Public key ditambahkan ke administrators_authorized_keys' +} + +icacls $authFile /inheritance:r | Out-Null +icacls $authFile /grant 'SYSTEM:(F)' | Out-Null +icacls $authFile /grant 'Administrators:(F)' | Out-Null + +# Pastikan pubkey auth aktif +$sshdConfig = 'C:\ProgramData\ssh\sshd_config' +if (Test-Path $sshdConfig) { + $cfg = Get-Content $sshdConfig -Raw + if ($cfg -match '(?m)^#?\s*PubkeyAuthentication\s+no') { + Write-Warning 'PubkeyAuthentication disabled di sshd_config — ubah manual ke yes lalu restart sshd' + } +} + +Restart-Service sshd +Write-Host 'sshd restarted.' +Write-Host '' +Write-Host 'Selesai. Tes dari laptop:' +Write-Host ' ssh multimedia hostname' diff --git a/server-connection/.env.example b/server-connection/.env.example new file mode 100644 index 0000000..e9f59d7 --- /dev/null +++ b/server-connection/.env.example @@ -0,0 +1,24 @@ +# .env.example — server-connection (monorepo index) +# Copy ke .env per sub-app — lihat path masing-masing + +# --- geonet-console (production) --- +# File: geonet-console/.env.example +CONSOLE_APP_URL=https://console.gisportal.id +CONSOLE_API_BASE=https://console.gisportal.id/api/v1 + +# --- Shared infra --- +LDAP_HOST=10.100.1.40 +LDAP_PORT=389 +DB_HOST_PG=10.100.1.25 +REVERSE_PROXY_HOST=10.100.1.24 +QNAP_OSS_HOST=file.gisportal.id + +# --- Zammad integration --- +ZAMMAD_API_URL=https://zammad.gisportal.id +ZAMMAD_API_TOKEN= + +# --- Mailcow (feedback email) --- +MAILCOW_IMAP_HOST=sync.geonet.co.id +MAILCOW_IMAP_PORT=993 + +# Docs: docs/system-requirements.md | docs/guide/migration.md diff --git a/server-connection/AGENTS.md b/server-connection/AGENTS.md index 0785e31..a05ae0e 100644 --- a/server-connection/AGENTS.md +++ b/server-connection/AGENTS.md @@ -1,135 +1,36 @@ -# Cursor Agent — server-connection +# AGENTS.md — Cold Start -Proyek ini memiliki **Cursor project rules** aktif di `.cursor/rules/`. +> Project: `server-connection/` +> Sesi terakhir: [docs/ai-session-summary.md](./docs/ai-session-summary.md) +> Peta: [docs/context-index.md](./docs/context-index.md) +> Env template: [.env.example](./.env.example) -## Rules aktif +## Apa ini? -| File | Scope | Isi | -|------|-------|-----| -| `00-project-context` | Selalu | Host SSH, deploy, struktur repo | -| `01-enterprise-principles` | Selalu | Prinsip enterprise & UX wajib | -| `02-implementation-status` | Selalu | Status fitur geonet-console (audit) | -| `03-ai-behavior` | Selalu | Perilaku agent, larangan, bahasa | -| `04-geonet-uiux` | `geonet-console/`, `databaselist/` | Standar UI/UX | -| `05-laravel-backend` | `*.php` di apps | Service layer, API, audit | -| `06-infrastructure` | `scripts/`, `server/` | SSH, Mikrotik, deploy | +Monorepo IT operations: **geonet-console** (Laravel API/portal), databaselist, sqlservercheck, deploy scripts. -## Aplikasi utama +## Aturan kritis -- **geonet-console** — https://console.gisportal.id -- **databaselist** — https://databaselist.gisportal.id -- **sqlservercheck** — https://sqlservercheck.gisportal.id +- **No hardcoded URL/domain/IP** — per-app `.env` dari `.env.example` +- No commit `.env`; secrets per stack di server +- No commit kecuali user minta +- **Deploy:** append [docs/version.md](./docs/version.md) per stack yang berubah +- Kerja di sub-app → baca `geonet-console/context-index.md` juga +- Detail Laravel/UI: `.cursor/rules/` (00–06) +- Pengetahuan penting **wajib ke docs** -## Dokumentasi sumber (referensi lengkap) - -- `Cursor-Enterprise-Full-Documentation/` — baseline enterprise -- `cursor-exsisting/` — audit UI/UX detail -- `cursor-exsisting-ask/` — status implementasi detail -- `rules`, `rules-adv` — requirement bisnis manual -- `server/ollama-nas-project-search-requirements.md` — requirement lengkap Ollama + NAS search + license extraction - ---- - -## Ollama + NAS Project Search (ringkasan agent) - -**Status:** direncanakan (belum diimplementasi di geonet-console). -**Dokumen lengkap:** `server/ollama-nas-project-search-requirements.md` - -### Ringkasan keputusan - -| Pertanyaan | Jawaban | -|------------|---------| -| Ollama bisa langsung scan `\\10.100.1.10\project`? | **Tidak** — perlu **indexer + PostgreSQL** | -| Multi-folder (project, Marketing, dll.)? | **Ya** — via env **indexer**, bukan env Ollama | -| Host Ollama POC & CPU | **VM `10.100.1.26` (aiopr)** — dedicated Ubuntu 22.04 | -| Host Ollama GPU (target) | Migrasi **Windows 11 + GPU** (~6 bulan) → ganti `OLLAMA_BASE_URL` | -| Model Ubuntu → Windows portable? | **Ya** — copy `~/.ollama/models/` atau `ollama pull` ulang | -| Indeks RAG pindah ke PC Windows? | **Tidak perlu** — tetap di PostgreSQL `10.100.1.25` | -| License code / tanggal expired dari PDF? | **Ya** — `license_registry` + parser terstruktur (bukan tebakan LLM) | - -**Prinsip:** Ollama = bahasa alami. Indexer + PostgreSQL = otak pencarian. NAS = storage saja. - -### Arsitektur +## Lanjut kerja ``` -User → geonet-console (chat UI / API v1) - │ - ▼ -Project Search Service (Laravel / worker) - - query natural language, filter source, audit log - │ - ┌────┴────┐ - ▼ ▼ -PostgreSQL Ollama 10.100.1.26 (aiopr) -10.100.1.25 qwen2.5 + nomic-embed-text -- project_index -- project_chunks -- license_registry -- pgvector - ▲ - │ -Indexer Worker (VM) — mount SMB QNAP, crawl, ekstrak, embed - │ - ▼ -QNAP TS-932X 10.100.1.10 (\\10.100.1.10\project, Marketing, …) +1. AGENTS.md → docs/ai-session-summary.md → STOP +2. On-demand: docs/todo.md, geonet-console/docapi/, docs/server.md ``` -| Host | IP | Peran | -|------|-----|-------| -| QNAP NAS | `10.100.1.10` | SMB storage (~2,6 TB project, ~1,4 juta file) | -| **Ollama VM** | **`10.100.1.26`** | **Ollama inference + indexer POC** (`aiopr`) | -| Reverse proxy | `10.100.1.24` | Nginx, Docker, geonet-console | -| Main database | `10.100.1.25` | PostgreSQL + pgvector | -| geonet-console | via `.24` | UI + API | - -SSH: `.\scripts\ssh-ollama.ps1`, `.\scripts\ssh-qnap.ps1`, `.\scripts\ssh-remote.ps1` - -### API (target geonet-console) - -| Endpoint | Method | Fungsi | -|----------|--------|--------| -| `/api/v1/project-search/ask` | POST | Query natural language + optional `sources[]` | -| `/api/v1/project-search/index/status` | GET | Status indeks per source | -| `/api/v1/project-search/sources` | GET | Daftar source dari env | -| `/api/v1/license-search/ask` | POST | Query license natural language | -| `/api/v1/license-search/code/{code}` | GET | Lookup exact license code | -| `/api/v1/license-search/expiring` | GET | License mendekati expired | -| `/api/v1/license-search/reindex` | POST | Re-parse file (admin, audit) | - -**Wajib enterprise:** LDAP/API token, audit log, throttle, RBAC per `source_id`. - -### Timeline rekomendasi - -| Tahap | Durasi | Deliverable | -|-------|--------|-------------| -| POC metadata | 1–2 minggu | Index `project`, chat di console | -| Multi-source | +1 minggu | Marketing/GIS via env | -| Fase 2 RAG | 2–4 minggu | pgvector + ekstrak dokumen | -| License extraction P1 | +1–2 minggu | `license_registry` + parser GM & ESRI | -| Migrasi GPU | ~6 bulan | Windows 11 + GPU, ganti `OLLAMA_BASE_URL` | - -### Checklist go-live - -#### Host `10.100.1.26` - -- [x] vCPU **16** (upgraded 2026-06-15) -- [ ] Ollama + model terinstall -- [ ] `ufw` + bind `11434` internal -- [ ] Mount SMB QNAP untuk indexer POC - -#### Stack - -- [ ] PostgreSQL pgvector + `project_index` di `10.100.1.25` -- [ ] `OLLAMA_BASE_URL=http://10.100.1.26:11434` di geonet-console -- [ ] Indeks awal `project` (metadata) selesai -- [ ] Audit log pencarian aktif -- [ ] RBAC source sensitif (Marketing/Sales) -- [ ] Rencana migrasi Windows GPU terdokumentasi -- [ ] Tabel `license_registry` + parser P1 (`geonet_global_mapper_v1`, `esri_certificate_id_v1`) -- [ ] Index license folder `project/2025`–`2026` terlebih dahulu - ---- - -## Verifikasi agent aktif +## Pointer -Di Cursor: **Settings → Rules** — pastikan project rules dari `.cursor/rules/` terdeteksi. +| Butuh | Buka | +|-------|------| +| geonet-console | [geonet-console/context-index.md](./geonet-console/context-index.md) | +| Versi | [docs/version.md](./docs/version.md) | +| Server | [docs/server.md](./docs/server.md) | +| API | [geonet-console/docapi/](./geonet-console/docapi/) | diff --git a/server-connection/docs/ai-session-summary.md b/server-connection/docs/ai-session-summary.md new file mode 100644 index 0000000..e3a0eec --- /dev/null +++ b/server-connection/docs/ai-session-summary.md @@ -0,0 +1,20 @@ +# AI Session Summary + +```yaml +session: 2026-07-06-docs-bootstrap +project: server-connection/ +version: 2.0.1 +status: ready +next: Lanjutkan backlog geonet-console / Zammad feedback +agent: Cursor +``` + +## TL;DR + +- Bootstrap SSOT docs (version.md, guide/, system-requirements.md) +- geonet-console production; Zammad feedback sync via `ZammadTicketService` + +## Lanjut + +1. Baca `geonet-console/context-index.md` untuk task API +2. Deploy → append `docs/version.md` diff --git a/server-connection/docs/changelog.md b/server-connection/docs/changelog.md index 0592cd4..d3412da 100644 --- a/server-connection/docs/changelog.md +++ b/server-connection/docs/changelog.md @@ -2,7 +2,13 @@ --- -## [Doc 1.1.0] — 2026-07-02 +## [2.0.1] — 2026-07-06 + +### Added +- Bootstrap AI-Agent-Standards: `docs/version.md`, `system-requirements.md`, `guide/`, root `.env.example` +- `docs/ai-session-summary.md` + +--- ### Changed - `docs/context-index.md` — tandai `.cursor/context-index.md` sebagai Deprecated diff --git a/server-connection/docs/context-index.md b/server-connection/docs/context-index.md index 0db3add..3f9754d 100644 --- a/server-connection/docs/context-index.md +++ b/server-connection/docs/context-index.md @@ -1,7 +1,8 @@ # Context Index — server-connection ⭐ AI Entry Point -> **Terakhir Diperbarui:** 2026-06-29 -> **Versi:** 2.0.0 +> **Terakhir Diperbarui:** 2026-07-06 +> **Versi:** 2.0.1 — [version.md](./version.md) +> **Cold start:** [../AGENTS.md](../AGENTS.md) --- diff --git a/server-connection/docs/guide/README.md b/server-connection/docs/guide/README.md new file mode 100644 index 0000000..a9b5791 --- /dev/null +++ b/server-connection/docs/guide/README.md @@ -0,0 +1,7 @@ +# Guides — server-connection + +| Guide | Path | +|-------|------| +| Migrasi server/domain | [migration.md](./migration.md) | +| Deploy | [../deployment.md](../deployment.md) | +| geonet-console API | [../geonet-console/docapi/](../geonet-console/docapi/) | diff --git a/server-connection/docs/guide/migration.md b/server-connection/docs/guide/migration.md new file mode 100644 index 0000000..e62a2be --- /dev/null +++ b/server-connection/docs/guide/migration.md @@ -0,0 +1,18 @@ +# Migration Guide — server-connection + +## Stack paths (`.24`) + +| App | Path | +|-----|------| +| geonet-console | `/opt/stacks/geonet-console` | +| databaselist | `/opt/stacks/databaselist` | +| sqlservercheck | `/opt/stacks/sqlservercheck` | + +## Cutover domain + +1. Update nginx vhost di `10.100.1.24` +2. Update `APP_URL` di `.env` stack +3. `docker compose up -d` + migrate jika Laravel +4. Append [../version.md](../version.md) + +Detail nginx: `nginx/docs/server.md`. diff --git a/server-connection/docs/system-requirements.md b/server-connection/docs/system-requirements.md new file mode 100644 index 0000000..ac68441 --- /dev/null +++ b/server-connection/docs/system-requirements.md @@ -0,0 +1,26 @@ +# System Requirements — server-connection + +| Field | Value | +|-------|-------| +| Project | `server-connection/` | +| Tipe | monorepo (Laravel apps + scripts) | +| Last updated | 2026-07-06 | + +## Runtime per app + +| App | Stack | Host deploy | +|-----|-------|-------------| +| geonet-console | PHP 8.2+, Laravel 11/12 | `10.100.1.24` Docker | +| databaselist | Laravel legacy | `10.100.1.24` | +| sqlservercheck | PHP | `10.100.1.24` | + +## Shared dependency + +| Service | Host | +|---------|------| +| PostgreSQL | `10.100.1.25` | +| LDAP AD | `10.100.1.40:389` | +| nginx | `10.100.1.24` | +| QNAP OSS | `10.100.1.10` | + +Env per app: `geonet-console/.env.example`. Index: [../.env.example](../.env.example). diff --git a/server-connection/docs/version.md b/server-connection/docs/version.md new file mode 100644 index 0000000..35df21d --- /dev/null +++ b/server-connection/docs/version.md @@ -0,0 +1,22 @@ +# Version History — server-connection + +Append per deploy per stack (geonet-console, databaselist, sqlservercheck). + +--- + +## [2.0.1] - 2026-07-06 + +- Bootstrap AI-Agent-Standards: version.md, system-requirements.md, guide/, root .env.example +- ZammadTicketService + feedback Zammad fields (geonet-console) + +--- + +## [2.0.0] - 2026-06-29 + +- Dokumentasi enterprise flat files (`docs/context-index.md`, architecture, ADR) + +--- + +## [1.0.0] - 2026-06-01 + +- geonet-console production di `console.gisportal.id` diff --git a/server-connection/geonet-console/.env.example b/server-connection/geonet-console/.env.example index 0847ac6..0ff1b51 100644 --- a/server-connection/geonet-console/.env.example +++ b/server-connection/geonet-console/.env.example @@ -156,3 +156,13 @@ OSS_PUBLIC_URL=http://file.gisportal.id:8010 TZ=Asia/Jakarta + + +# Zammad ticketing (feedback → auto-create ticket) +ZAMMAD_ENABLED=true +ZAMMAD_BASE_URL=https://zammad.gisportal.id +ZAMMAD_API_TOKEN= +ZAMMAD_DEFAULT_GROUP=Users +ZAMMAD_FALLBACK_CUSTOMER=support@geonet.co.id +ZAMMAD_TIMEOUT=30 + diff --git a/server-connection/geonet-console/app/Http/Controllers/Api/V1/AiChatController.php b/server-connection/geonet-console/app/Http/Controllers/Api/V1/AiChatController.php new file mode 100644 index 0000000..3c26332 --- /dev/null +++ b/server-connection/geonet-console/app/Http/Controllers/Api/V1/AiChatController.php @@ -0,0 +1,73 @@ +aiChat->isAvailable()) { + return $this->fail('AI service belum dikonfigurasi (OLLAMA_BASE_URL kosong).', 'service_unavailable', 503); + } + + $validated = $request->validate([ + 'message' => ['required', 'string', 'min:2', 'max:2000'], + 'history' => ['sometimes', 'array', 'max:20'], + 'history.*.role' => ['required_with:history', 'string', 'in:user,assistant'], + 'history.*.content' => ['required_with:history', 'string', 'max:4000'], + ]); + + /** @var ApiActor|null $actor */ + $actor = $request->attributes->get('api_actor'); + $username = $actor instanceof ApiActor ? $actor->identifier : 'unknown'; + + try { + $result = $this->aiChat->chat( + query: $validated['message'], + username: $username, + displayName: $username, + jobTitle: '', + history: $validated['history'] ?? [], + ); + + return $this->ok([ + 'answer' => $result['answer'], + 'context_count' => $result['meta']['context_count'], + 'model' => $result['meta']['model'], + ]); + } catch (Throwable $e) { + return $this->fail('Gagal memproses permintaan AI: '.$e->getMessage(), 'server_error', 500); + } + } + + /** + * GET /api/v1/ai/status + */ + public function status(): JsonResponse + { + return $this->ok([ + 'available' => $this->aiChat->isAvailable(), + 'base_url' => config('ollama.base_url') ?: null, + 'model' => config('ollama.chat_model'), + ]); + } +} diff --git a/server-connection/geonet-console/app/Http/Controllers/Api/V1/FeedbackController.php b/server-connection/geonet-console/app/Http/Controllers/Api/V1/FeedbackController.php index 9b2d599..8873844 100644 --- a/server-connection/geonet-console/app/Http/Controllers/Api/V1/FeedbackController.php +++ b/server-connection/geonet-console/app/Http/Controllers/Api/V1/FeedbackController.php @@ -5,6 +5,7 @@ namespace App\Http\Controllers\Api\V1; use App\Http\Controllers\Api\Concerns\RespondsWithJson; use App\Http\Controllers\Controller; use App\Models\Feedback; +use App\Services\ZammadTicketService; use App\Support\ApiActor; use Illuminate\Http\JsonResponse; use Illuminate\Http\Request; @@ -14,6 +15,11 @@ class FeedbackController extends Controller { use RespondsWithJson; + public function __construct( + private readonly ZammadTicketService $zammadTickets, + ) { + } + public function store(Request $request): JsonResponse { /** @var ApiActor $actor */ @@ -47,10 +53,10 @@ class FeedbackController extends Controller 'reported_at' => isset($ctx['reported_at']) ? now()->parse($ctx['reported_at']) : now(), ]); - return $this->ok([ - 'id' => $feedback->id, - 'status' => $feedback->status, - ], [], 201); + $this->zammadTickets->createTicketFromFeedback($feedback, $actor); + $feedback->refresh(); + + return $this->ok($this->serializeFeedback($feedback), [], 201); } public function index(Request $request): JsonResponse @@ -94,6 +100,21 @@ class FeedbackController extends Controller $feedback->update($validated); - return $this->ok($feedback->only(['id', 'status', 'admin_note'])); + return $this->ok($this->serializeFeedback($feedback)); + } + + /** + * @return array + */ + private function serializeFeedback(Feedback $feedback): array + { + return [ + 'id' => $feedback->id, + 'status' => $feedback->status, + 'zammad_ticket_id' => $feedback->zammad_ticket_id, + 'zammad_ticket_number' => $feedback->zammad_ticket_number, + 'zammad_ticket_url' => $this->zammadTickets->ticketUrl($feedback), + 'zammad_sync_error' => $feedback->zammad_sync_error, + ]; } } diff --git a/server-connection/geonet-console/app/Models/Feedback.php b/server-connection/geonet-console/app/Models/Feedback.php index 19989cd..69d4465 100644 --- a/server-connection/geonet-console/app/Models/Feedback.php +++ b/server-connection/geonet-console/app/Models/Feedback.php @@ -18,9 +18,14 @@ class Feedback extends Model 'user_agent', 'reported_at', 'admin_note', + 'zammad_ticket_id', + 'zammad_ticket_number', + 'zammad_synced_at', + 'zammad_sync_error', ]; protected $casts = [ 'reported_at' => 'datetime', + 'zammad_synced_at' => 'datetime', ]; } diff --git a/server-connection/geonet-console/app/Services/AiChatService.php b/server-connection/geonet-console/app/Services/AiChatService.php new file mode 100644 index 0000000..f7707ed --- /dev/null +++ b/server-connection/geonet-console/app/Services/AiChatService.php @@ -0,0 +1,171 @@ +ollama->isConfigured(); + } + + /** + * @param array $history + * @return array{answer: string, chunks: array>, meta: array} + */ + public function chat( + string $query, + string $username, + string $displayName, + string $jobTitle = '', + array $history = [], + int $contextLimit = 5 + ): array { + $chunks = $this->retrieveContext($query, $contextLimit); + $answer = $this->generate($query, $username, $displayName, $jobTitle, $chunks, $history); + + return [ + 'answer' => $answer, + 'chunks' => $chunks, + 'meta' => [ + 'query' => $query, + 'context_count' => count($chunks), + 'model' => config('ollama.chat_model'), + ], + ]; + } + + /** + * Embed query → similarity search di pgvector code_chunks. + * + * @return array> + */ + private function retrieveContext(string $query, int $limit): array + { + $baseUrl = rtrim((string) config('ollama.base_url'), '/'); + $embedModel = (string) config('ollama.embed_model', 'nomic-embed-text'); + + try { + $resp = Http::timeout(30) + ->post($baseUrl.'/api/embeddings', [ + 'model' => $embedModel, + 'prompt' => $query, + ]); + + if (! $resp->successful()) { + return []; + } + + $embedding = $resp->json('embedding'); + if (! is_array($embedding) || count($embedding) !== 768) { + return []; + } + + $pgHost = (string) config('pgvector.host', '10.100.1.24'); + $pgPort = (int) config('pgvector.port', 5433); + $pgDb = (string) config('pgvector.database', 'geonet_project_search'); + $pgUser = (string) config('pgvector.username', 'geonet_ai'); + $pgPass = (string) config('pgvector.password', ''); + + $dsn = "pgsql:host={$pgHost};port={$pgPort};dbname={$pgDb}"; + $pdo = new \PDO($dsn, $pgUser, $pgPass, [\PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION]); + + $vectorStr = '['.implode(',', $embedding).']'; + $sql = " + SELECT file_path, start_line, end_line, language, repo, + content, + 1 - (embedding <=> :vec::vector) AS similarity + FROM code_chunks + ORDER BY embedding <=> :vec2::vector + LIMIT :limit + "; + + $stmt = $pdo->prepare($sql); + $stmt->execute([':vec' => $vectorStr, ':vec2' => $vectorStr, ':limit' => $limit]); + + return array_map(fn ($row) => [ + 'repo' => $row['repo'], + 'file_path' => $row['file_path'], + 'start_line' => (int) $row['start_line'], + 'end_line' => (int) $row['end_line'], + 'language' => $row['language'], + 'content' => $row['content'], + 'similarity' => round((float) $row['similarity'], 4), + ], $stmt->fetchAll(\PDO::FETCH_ASSOC)); + + } catch (Throwable) { + return []; + } + } + + /** + * @param array> $chunks + * @param array $history + */ + private function generate( + string $query, + string $username, + string $displayName, + string $jobTitle, + array $chunks, + array $history + ): string { + $contextBlock = ''; + if ($chunks !== []) { + $contextBlock = "\n\n### Konteks dari Codebase:\n"; + foreach ($chunks as $i => $chunk) { + $contextBlock .= sprintf( + "\n[%d] %s:%d-%d\n```%s\n%s\n```\n", + $i + 1, + $chunk['file_path'], + $chunk['start_line'], + $chunk['end_line'], + $chunk['language'] ?? '', + trim($chunk['content']) + ); + } + } + + $identity = "Nama: {$displayName}"; + if ($jobTitle !== '') { + $identity .= ", Jabatan: {$jobTitle}"; + } + + $system = << 'system', 'content' => $system]]; + + foreach (array_slice($history, -10) as $item) { + $role = $item['role'] ?? ''; + $content = $item['content'] ?? ''; + if (! in_array($role, ['user', 'assistant'], true) || $content === '') { + continue; + } + $messages[] = ['role' => $role, 'content' => $content]; + } + + $userContent = $query.$contextBlock; + $messages[] = ['role' => 'user', 'content' => $userContent]; + + try { + return $this->ollama->chat($messages); + } catch (Throwable $e) { + return 'Maaf, AI sedang tidak tersedia: '.$e->getMessage(); + } + } +} diff --git a/server-connection/geonet-console/app/Services/ZammadTicketService.php b/server-connection/geonet-console/app/Services/ZammadTicketService.php new file mode 100644 index 0000000..f201619 --- /dev/null +++ b/server-connection/geonet-console/app/Services/ZammadTicketService.php @@ -0,0 +1,182 @@ +isConfigured()) { + $this->markSyncError($feedback, 'Zammad integration is not configured.'); + + return null; + } + + $customerEmail = $this->resolveCustomerEmail($feedback, $actor); + if ($customerEmail === null) { + $this->markSyncError($feedback, 'No valid customer email for Zammad ticket.'); + + return null; + } + + $payload = [ + 'title' => $this->buildTitle($feedback), + 'group' => config('zammad.default_group'), + 'customer_id' => 'guess:'.$customerEmail, + 'article' => [ + 'subject' => $this->buildTitle($feedback), + 'body' => $this->buildArticleBody($feedback), + 'type' => 'web', + 'internal' => false, + ], + ]; + + try { + $response = Http::timeout((int) config('zammad.timeout', 30)) + ->acceptJson() + ->withHeaders([ + 'Authorization' => 'Token token='.config('zammad.api_token'), + ]) + ->post(config('zammad.base_url').'/api/v1/tickets', $payload); + } catch (\Throwable $e) { + $this->markSyncError($feedback, 'Zammad request failed: '.$e->getMessage()); + Log::warning('Zammad ticket create failed', [ + 'feedback_id' => $feedback->id, + 'error' => $e->getMessage(), + ]); + + return null; + } + + if (! $response->successful()) { + $message = data_get($response->json(), 'error_human') + ?? data_get($response->json(), 'error') + ?? 'HTTP '.$response->status(); + $this->markSyncError($feedback, (string) $message); + Log::warning('Zammad ticket create rejected', [ + 'feedback_id' => $feedback->id, + 'status' => $response->status(), + 'body' => $response->json(), + ]); + + return null; + } + + $ticketId = data_get($response->json(), 'id'); + $ticketNumber = data_get($response->json(), 'number'); + + if (! is_numeric($ticketId)) { + $this->markSyncError($feedback, 'Zammad response missing ticket id.'); + + return null; + } + + $syncedAt = now(); + $feedback->forceFill([ + 'zammad_ticket_id' => (int) $ticketId, + 'zammad_ticket_number' => is_scalar($ticketNumber) ? (string) $ticketNumber : null, + 'zammad_synced_at' => $syncedAt, + 'zammad_sync_error' => null, + ])->save(); + + return [ + 'zammad_ticket_id' => (int) $ticketId, + 'zammad_ticket_number' => is_scalar($ticketNumber) ? (string) $ticketNumber : (string) $ticketId, + 'zammad_synced_at' => $syncedAt, + ]; + } + + public function ticketUrl(Feedback $feedback): ?string + { + if ($feedback->zammad_ticket_id === null) { + return null; + } + + return config('zammad.base_url').'/#ticket/zoom/'.$feedback->zammad_ticket_id; + } + + private function resolveCustomerEmail(Feedback $feedback, ?ApiActor $actor): ?string + { + foreach ([$feedback->reporter, $actor?->identifier] as $candidate) { + if (is_string($candidate) && filter_var($candidate, FILTER_VALIDATE_EMAIL)) { + return Str::lower($candidate); + } + } + + $fallback = (string) config('zammad.fallback_customer'); + if ($fallback !== '' && filter_var($fallback, FILTER_VALIDATE_EMAIL)) { + return Str::lower($fallback); + } + + return null; + } + + private function buildTitle(Feedback $feedback): string + { + $typeLabel = match ($feedback->type) { + 'bug' => 'Bug', + 'suggestion' => 'Saran', + default => 'Feedback', + }; + + return sprintf('[%s] %s', $typeLabel, $feedback->title); + } + + private function buildArticleBody(Feedback $feedback): string + { + $lines = [ + $feedback->message, + '', + '---', + 'Feedback #'.$feedback->id, + 'Tipe: '.$feedback->type, + ]; + + if ($feedback->reporter) { + $lines[] = 'Pelapor: '.$feedback->reporter; + } + if ($feedback->reporter_name) { + $lines[] = 'Nama: '.$feedback->reporter_name; + } + if ($feedback->page) { + $lines[] = 'Halaman: '.$feedback->page; + } + if ($feedback->url) { + $lines[] = 'URL: '.$feedback->url; + } + if ($feedback->user_agent) { + $lines[] = 'User-Agent: '.$feedback->user_agent; + } + if ($feedback->reported_at) { + $lines[] = 'Dilaporkan: '.$feedback->reported_at->toIso8601String(); + } + + return implode("\n", $lines); + } + + private function markSyncError(Feedback $feedback, string $message): void + { + $feedback->forceFill([ + 'zammad_sync_error' => Str::limit($message, 1000), + ])->save(); + } +} diff --git a/server-connection/geonet-console/compose.yaml b/server-connection/geonet-console/compose.yaml index 66a8af6..66a7bbd 100644 --- a/server-connection/geonet-console/compose.yaml +++ b/server-connection/geonet-console/compose.yaml @@ -25,6 +25,9 @@ services: image: geonet-console:latest container_name: geonet-console restart: unless-stopped + dns: + - 203.142.82.222 + - 203.142.84.222 depends_on: audit-postgres: condition: service_healthy diff --git a/server-connection/geonet-console/config/ollama.php b/server-connection/geonet-console/config/ollama.php index 1b62618..1a242d4 100644 --- a/server-connection/geonet-console/config/ollama.php +++ b/server-connection/geonet-console/config/ollama.php @@ -1,8 +1,8 @@ rtrim((string) env('OLLAMA_BASE_URL', 'http://127.0.0.1:11434'), '/'), - 'chat_model' => (string) env('OLLAMA_CHAT_MODEL', 'qwen2.5:7b'), + 'base_url' => rtrim((string) env('OLLAMA_BASE_URL', 'http://10.100.1.14:11434'), '/'), + 'chat_model' => (string) env('OLLAMA_CHAT_MODEL', 'qwen2.5-coder:14b'), 'embed_model' => (string) env('OLLAMA_EMBED_MODEL', 'nomic-embed-text'), - 'timeout' => (int) env('OLLAMA_TIMEOUT', 120), + 'timeout' => (int) env('OLLAMA_TIMEOUT', 120), ]; diff --git a/server-connection/geonet-console/config/pgvector.php b/server-connection/geonet-console/config/pgvector.php new file mode 100644 index 0000000..8e6a914 --- /dev/null +++ b/server-connection/geonet-console/config/pgvector.php @@ -0,0 +1,9 @@ + env('PGVECTOR_HOST', '10.100.1.24'), + 'port' => (int) env('PGVECTOR_PORT', 5433), + 'database' => env('PGVECTOR_DB', 'geonet_project_search'), + 'username' => env('PGVECTOR_USER', 'geonet_ai'), + 'password' => env('PGVECTOR_PASSWORD', ''), +]; diff --git a/server-connection/geonet-console/config/zammad.php b/server-connection/geonet-console/config/zammad.php new file mode 100644 index 0000000..a2c5bc4 --- /dev/null +++ b/server-connection/geonet-console/config/zammad.php @@ -0,0 +1,10 @@ + filter_var(env('ZAMMAD_ENABLED', true), FILTER_VALIDATE_BOOL), + 'base_url' => rtrim((string) env('ZAMMAD_BASE_URL', 'https://zammad.gisportal.id'), '/'), + 'api_token' => (string) env('ZAMMAD_API_TOKEN', ''), + 'timeout' => (int) env('ZAMMAD_TIMEOUT', 30), + 'default_group' => (string) env('ZAMMAD_DEFAULT_GROUP', 'Users'), + 'fallback_customer' => (string) env('ZAMMAD_FALLBACK_CUSTOMER', 'support@geonet.co.id'), +]; diff --git a/server-connection/geonet-console/database/migrations/2026_07_03_000001_add_zammad_fields_to_feedback_table.php b/server-connection/geonet-console/database/migrations/2026_07_03_000001_add_zammad_fields_to_feedback_table.php new file mode 100644 index 0000000..629b6ac --- /dev/null +++ b/server-connection/geonet-console/database/migrations/2026_07_03_000001_add_zammad_fields_to_feedback_table.php @@ -0,0 +1,33 @@ +unsignedBigInteger('zammad_ticket_id')->nullable()->after('admin_note'); + $table->string('zammad_ticket_number', 32)->nullable()->after('zammad_ticket_id'); + $table->timestamp('zammad_synced_at')->nullable()->after('zammad_ticket_number'); + $table->string('zammad_sync_error', 1000)->nullable()->after('zammad_synced_at'); + + $table->index('zammad_ticket_id'); + }); + } + + public function down(): void + { + Schema::table('feedback', function (Blueprint $table) { + $table->dropIndex(['zammad_ticket_id']); + $table->dropColumn([ + 'zammad_ticket_id', + 'zammad_ticket_number', + 'zammad_synced_at', + 'zammad_sync_error', + ]); + }); + } +}; diff --git a/server-connection/geonet-console/docapi/index.md b/server-connection/geonet-console/docapi/index.md index cd27226..ca1ad19 100644 --- a/server-connection/geonet-console/docapi/index.md +++ b/server-connection/geonet-console/docapi/index.md @@ -71,6 +71,16 @@ Base URL: `https://console.gisportal.id/api/v1` --- +## Feedback + +| Method | Endpoint | Auth | Scope | Deskripsi | Dokumen | +|--------|----------|------|-------|-----------|---------| +| POST | `/feedback` | JWT / API Token | — | Kirim feedback (+ tiket Zammad) | [store.md](./services/feedback/store.md) | +| GET | `/feedback` | JWT / API Token | admin | List feedback | — | +| PATCH | `/feedback/{id}` | JWT / API Token | admin | Update status feedback | — | + +--- + ## Project Search | Method | Endpoint | Auth | Scope | Deskripsi | Dokumen | diff --git a/server-connection/geonet-console/docapi/services/feedback/store.md b/server-connection/geonet-console/docapi/services/feedback/store.md new file mode 100644 index 0000000..3788cf2 --- /dev/null +++ b/server-connection/geonet-console/docapi/services/feedback/store.md @@ -0,0 +1,83 @@ +# POST /api/v1/feedback — Buat feedback (+ tiket Zammad) + +`POST https://console.gisportal.id/api/v1/feedback` + +Auth: JWT atau API Token (scope sesuai route middleware). + +--- + +## Request body + +```json +{ + "type": "bug", + "title": "Tombol simpan tidak merespons", + "message": "Saat klik Simpan di halaman profil, tidak ada reaksi.", + "context": { + "page": "/profile", + "url": "https://my.gisportal.id/profile", + "user_agent": "Mozilla/5.0 ...", + "reporter": "rbsetiawan", + "reporter_name": "RB Setiawan", + "reported_at": "2026-07-03T10:00:00+07:00" + } +} +``` + +| Field | Wajib | Keterangan | +|-------|-------|------------| +| `type` | ✅ | `bug`, `suggestion`, `other` | +| `title` | ✅ | Max 120 karakter | +| `message` | ✅ | Max 5000 karakter | +| `context.reporter` | — | Username / email pelapor | +| `context.reporter_name` | — | Nama tampilan | + +--- + +## Response 201 + +Feedback selalu disimpan. Jika integrasi Zammad aktif (`ZAMMAD_API_TOKEN`), tiket dibuat otomatis. + +```json +{ + "data": { + "id": 12, + "status": "open", + "zammad_ticket_id": 10042, + "zammad_ticket_number": "10042", + "zammad_ticket_url": "https://zammad.gisportal.id/#ticket/zoom/10042", + "zammad_sync_error": null + }, + "meta": {}, + "error": null +} +``` + +Jika sync Zammad gagal, `id` dan `status` tetap ada; `zammad_ticket_*` null dan `zammad_sync_error` berisi pesan singkat. + +--- + +## Env server + +| Variable | Contoh | +|----------|--------| +| `ZAMMAD_ENABLED` | `true` | +| `ZAMMAD_BASE_URL` | `https://zammad.gisportal.id` | +| `ZAMMAD_API_TOKEN` | Token `fe-ticketing-pwa` dari Zammad | +| `ZAMMAD_DEFAULT_GROUP` | `Users` | + +Token disimpan di server Zammad: `/opt/stacks/zammad/.fe-ticketing-token` + +--- + +## FE (my.gisportal.id) + +Setelah sukses, tampilkan ke user: + +```tsx +if (data.zammad_ticket_number) { + toast.success(`Tiket #${data.zammad_ticket_number} dibuat. Tim support akan menindaklanjuti.`); +} +``` + +Lihat juga `Zammad/docs/notes/fe-ticketing-integration.md`. diff --git a/server-connection/geonet-console/docs/ai-session-summary.md b/server-connection/geonet-console/docs/ai-session-summary.md new file mode 100644 index 0000000..59eefaa --- /dev/null +++ b/server-connection/geonet-console/docs/ai-session-summary.md @@ -0,0 +1,79 @@ +# AI Session Summary — geonet-console + +```yaml +session: 2026-07-06-ai-chat-endpoint +project: server-connection/geonet-console +version: ai-fase3 +status: deployed +next: UI chat Super Apps PWA + user memory + ai.chat permission guard +agent: Cascade +branch: main +``` + +## TL;DR + +- `POST /api/v1/ai/chat` + `GET /api/v1/ai/status` live di production (`console.gisportal.id`) +- RAG pipeline: embed query → pgvector `10.100.1.24:5433` → 5 context chunks → Ollama `10.100.1.14:11434` → jawaban +- Verified: query "route untuk feedback" → jawab `POST /api/v1/feedback` dengan akurat + +## Files baru + +| File | Fungsi | +|------|--------| +| `app/Services/AiChatService.php` | Embed query, similarity search pgvector, generate via Ollama | +| `app/Http/Controllers/Api/V1/AiChatController.php` | Handler `POST /api/v1/ai/chat` + `GET /api/v1/ai/status` | +| `config/pgvector.php` | Config pgvector — baca env `PGVECTOR_HOST/PORT/DB/USER/PASSWORD` | + +## Files dimodifikasi + +| File | Perubahan | +|------|-----------| +| `config/ollama.php` | Default URL → `10.100.1.14:11434`, model → `qwen2.5-coder:14b` | +| `routes/api.php` | Tambah 2 route AI Chat, import `AiChatController` | + +## Env vars baru di server `.env` + +``` +OLLAMA_BASE_URL=http://10.100.1.14:11434 +OLLAMA_CHAT_MODEL=qwen2.5-coder:14b +OLLAMA_EMBED_MODEL=nomic-embed-text +PGVECTOR_HOST=10.100.1.24 +PGVECTOR_PORT=5433 +PGVECTOR_DB=geonet_project_search +PGVECTOR_USER=geonet_ai +PGVECTOR_PASSWORD= +``` + +## API endpoint + +| Method | Path | Auth | Keterangan | +|--------|------|------|-----------| +| `GET` | `/api/v1/ai/status` | Bearer | Cek ketersediaan + model aktif | +| `POST` | `/api/v1/ai/chat` | Bearer | Chat dengan RAG codebase | + +Request body `/ai/chat`: +```json +{ + "message": "pertanyaan...", + "history": [{"role":"user","content":"..."},{"role":"assistant","content":"..."}] +} +``` + +## Deploy notes + +- Image di-rebuild di `10.100.1.24` via `docker compose build geonet-console` +- **Bug:** jangan gunakan `scp config/*.php routes/api.php root@host:/path/config/` dalam satu perintah — `routes/api.php` akan tertimpa ke `config/api.php` +- Selalu deploy config dan routes terpisah + +## Lanjut dari sini + +1. **UI chat** di Super Apps PWA — React window, kirim ke `/api/v1/ai/chat` +2. **User memory** — `POST /api/v1/ai/memory`, simpan ke tabel `user_memory` di pgvector +3. **Permission guard** — tambah `ai.chat` ke `group_permissions`, guard di middleware +4. **Streaming** — opsional, tambah `stream: true` ke `OllamaService::chat()` + +## Jangan + +- Jangan hardcode `PGVECTOR_PASSWORD` di source — baca dari env +- Jangan expose `/api/v1/ai/chat` tanpa auth (`api.auth` middleware sudah aktif) +- Jangan rebuild image tanpa verifikasi `config/api.php` isi yang benar diff --git a/server-connection/geonet-console/routes/api.php b/server-connection/geonet-console/routes/api.php index cf64cb2..1531840 100644 --- a/server-connection/geonet-console/routes/api.php +++ b/server-connection/geonet-console/routes/api.php @@ -1,5 +1,6 @@ group(function () { Route::get('/service-tokens/expired', [ServiceTokenController::class, 'getExpired']) ->name('api.v1.service-tokens.expired'); + // AI Chat — on-premise via Ollama + pgvector RAG + Route::get('/ai/status', [AiChatController::class, 'status']) + ->name('api.v1.ai.status'); + Route::post('/ai/chat', [AiChatController::class, 'chat']) + ->middleware('throttle:30,1') + ->name('api.v1.ai.chat'); + // Feedback — bug reports & suggestions Route::post('/feedback', [FeedbackController::class, 'store']) ->middleware('throttle:30,1') diff --git a/server-connection/scripts/oss-create-bucket.php b/server-connection/scripts/oss-create-bucket.php new file mode 100644 index 0000000..08d0c91 --- /dev/null +++ b/server-connection/scripts/oss-create-bucket.php @@ -0,0 +1,78 @@ + 'latest', + 'region' => $region, + 'endpoint' => $endpoint, + 'use_path_style_endpoint' => true, + 'credentials' => [ + 'key' => $key, + 'secret' => $secret, + ], +]); + +echo "=== List buckets ===\n"; +foreach ($client->listBuckets()['Buckets'] ?? [] as $b) { + echo ' - ' . $b['Name'] . "\n"; +} + +if (!$client->doesBucketExist($bucket)) { + echo "Creating bucket: {$bucket}\n"; + $client->createBucket(['Bucket' => $bucket]); + echo "Created.\n"; +} else { + echo "Bucket already exists: {$bucket}\n"; +} + +$testKey = '_healthcheck/oss-setup-test.txt'; +$body = 'zammad-oss-test-' . gmdate('c'); + +$lastError = null; +for ($attempt = 1; $attempt <= 5; $attempt++) { + try { + $client->putObject([ + 'Bucket' => $bucket, + 'Key' => $testKey, + 'Body' => $body, + 'ContentType' => 'text/plain', + ]); + echo "Upload OK (attempt {$attempt}): {$testKey}\n"; + $lastError = null; + break; + } catch (Throwable $e) { + $lastError = $e; + echo "Upload attempt {$attempt} failed: " . $e->getMessage() . "\n"; + sleep(3); + } +} + +if ($lastError !== null) { + fwrite(STDERR, "Upload failed after retries. Bucket exists but write test did not pass.\n"); + exit(2); +} + +$got = (string) $client->getObject(['Bucket' => $bucket, 'Key' => $testKey])['Body']; +if ($got !== $body) { + fwrite(STDERR, "Download mismatch\n"); + exit(1); +} +echo "Download OK\n"; +echo "DONE: bucket {$bucket} ready (private — no public ACL set)\n";