Browse Source
Add AI-Agent-Standards templates, Zammad/Mailcow dual-domain docs, Ollama and Mikrotik VM audits with config backup, PC-Multimedia bootstrap, geonet-console Zammad/AI chat integration, and workspace registry updates. Co-authored-by: Cursor <cursoragent@cursor.com>master
253 changed files with 13069 additions and 450 deletions
@ -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 |
||||||
|
``` |
||||||
@ -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 |
||||||
@ -0,0 +1,56 @@ |
|||||||
|
# AI Session Summary |
||||||
|
|
||||||
|
<!-- CONTOH - max 80 baris, omit-if-N/A --> |
||||||
|
|
||||||
|
```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/) |
||||||
@ -0,0 +1,58 @@ |
|||||||
|
# Workspace Session |
||||||
|
|
||||||
|
<!-- CONTOH monorepo --> |
||||||
|
|
||||||
|
## 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) |
||||||
@ -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. |
||||||
@ -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. |
||||||
@ -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) |
||||||
@ -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. |
||||||
@ -0,0 +1,53 @@ |
|||||||
|
# Handover Checklist |
||||||
|
|
||||||
|
<!-- Gunakan sebelum commit/push. Ikuti TIER. --> |
||||||
|
|
||||||
|
## 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 |
||||||
@ -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 |
||||||
@ -0,0 +1,60 @@ |
|||||||
|
# AGENTS.md - Cold Start |
||||||
|
|
||||||
|
<!-- STRATEGY: UPDATE JARANG | Baca PERTAMA saat buka project. Max ~40 baris. --> |
||||||
|
<!-- Lokasi: root project (sibling docs/), BUKAN di dalam docs/ --> |
||||||
|
|
||||||
|
> 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. |
||||||
@ -0,0 +1,50 @@ |
|||||||
|
# ADR-{NNN}: {Judul Keputusan} |
||||||
|
|
||||||
|
<!-- STRATEGY: APPEND | Satu file per keputusan arsitektur --> |
||||||
|
|
||||||
|
**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} |
||||||
@ -0,0 +1,78 @@ |
|||||||
|
# AI Session Summary |
||||||
|
|
||||||
|
<!-- STRATEGY: OVERWRITE | Satu-satunya rolling session memory per project --> |
||||||
|
<!-- BATAS KERAS: max 80 baris / ~1500 token. Omit seksi N/A. --> |
||||||
|
<!-- READ: setelah AGENTS.md. Cukup TL;DR + Lanjut + Jangan untuk lanjut kerja. --> |
||||||
|
|
||||||
|
**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) |
||||||
|
|
||||||
|
<!-- Hapus seluruh blok Detail jika TL;DR sudah cukup. Max sisa file agar total <= 80 baris. --> |
||||||
|
|
||||||
|
### 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) |
||||||
@ -0,0 +1,44 @@ |
|||||||
|
# API Documentation |
||||||
|
|
||||||
|
<!-- STRATEGY: UPDATE | Wajib jika project menerapkan API atau framework API --> |
||||||
|
|
||||||
|
**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 | |
||||||
|
|------|---------| |
||||||
|
| | | |
||||||
@ -0,0 +1,46 @@ |
|||||||
|
# Changelog |
||||||
|
|
||||||
|
<!-- STRATEGY: APPEND | Riwayat permanen — jangan overwrite --> |
||||||
|
|
||||||
|
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} |
||||||
@ -0,0 +1,141 @@ |
|||||||
|
# Context Index |
||||||
|
|
||||||
|
<!-- STRATEGY: UPDATE | Peta navigasi domain - boleh tebal, berlapis --> |
||||||
|
<!-- READ: on-demand. Cold start = ../AGENTS.md dulu, lalu ai-session-summary.md --> |
||||||
|
|
||||||
|
> 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 |
||||||
@ -0,0 +1,30 @@ |
|||||||
|
# Guides |
||||||
|
|
||||||
|
<!-- STRATEGY: UPDATE | Wajib jika project punya prosedur step-by-step khusus --> |
||||||
|
|
||||||
|
**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} |
||||||
@ -0,0 +1,120 @@ |
|||||||
|
# Migration Guide — Server & Domain |
||||||
|
|
||||||
|
<!-- STRATEGY: UPDATE | Owner prosedur migrasi infra/domain project ini --> |
||||||
|
<!-- READ: saat pindah server, ganti IP, ganti domain, atau cutover env --> |
||||||
|
|
||||||
|
**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} | | |
||||||
@ -0,0 +1,52 @@ |
|||||||
|
# Issues |
||||||
|
|
||||||
|
<!-- STRATEGY: APPEND | Tandai resolved, jangan hapus history --> |
||||||
|
|
||||||
|
**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 | | | | |
||||||
@ -0,0 +1,71 @@ |
|||||||
|
# Project Status |
||||||
|
|
||||||
|
<!-- STRATEGY: UPDATE | Status berkelanjutan proyek --> |
||||||
|
|
||||||
|
> 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} |
||||||
@ -0,0 +1,93 @@ |
|||||||
|
# Server Inventory |
||||||
|
|
||||||
|
<!-- STRATEGY: UPDATE | Owner inventori server/infra project ini --> |
||||||
|
<!-- READ: on-demand saat deploy, debug koneksi, atau ubah infra --> |
||||||
|
<!-- JANGAN simpan password, private key, connection string ber-secret --> |
||||||
|
|
||||||
|
**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. |
||||||
@ -0,0 +1,105 @@ |
|||||||
|
# System Requirements |
||||||
|
|
||||||
|
<!-- STRATEGY: UPDATE | Owner spesifikasi minimum runtime/build/deploy project ini --> |
||||||
|
<!-- READ: on-demand saat setup baru, upgrade tool, atau migrasi server --> |
||||||
|
|
||||||
|
**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) |
||||||
@ -0,0 +1,42 @@ |
|||||||
|
# TODO |
||||||
|
|
||||||
|
<!-- STRATEGY: ACTIVE UPDATE | Priority aktif = single owner di file ini --> |
||||||
|
|
||||||
|
> 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) |
||||||
|
|
||||||
|
<!-- OVERWRITE tiap sesi — jangan menumpuk history lintas sesi. |
||||||
|
Riwayat permanen: changelog.md + version.md --> |
||||||
|
|
||||||
|
- [x] {task} - selesai {YYYY-MM-DD} |
||||||
@ -0,0 +1,29 @@ |
|||||||
|
# Version History |
||||||
|
|
||||||
|
<!-- STRATEGY: APPEND | Satu entri per perbaikan/perubahan — jangan overwrite entri lama --> |
||||||
|
|
||||||
|
**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 |
||||||
@ -0,0 +1,156 @@ |
|||||||
|
# Workspace Context |
||||||
|
|
||||||
|
<!-- STRATEGY: UPDATE JARANG | Konteks global monorepo --> |
||||||
|
|
||||||
|
> 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. |
||||||
@ -0,0 +1,71 @@ |
|||||||
|
# Workspace Session |
||||||
|
|
||||||
|
<!-- STRATEGY: OVERWRITE | Ringkasan lintas-project sesi ini (monorepo) --> |
||||||
|
<!-- READ: baca Active focus dulu; detail project on-demand via link --> |
||||||
|
<!-- BATAS: max ~50 baris / ~100 baris jika banyak project --> |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
## Active focus |
||||||
|
|
||||||
|
<!-- 1-3 baris per project yang dikerjakan - agent scan ini dulu --> |
||||||
|
|
||||||
|
- `{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) |
||||||
@ -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 |
||||||
@ -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) | |
||||||
@ -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. |
||||||
@ -0,0 +1,3 @@ |
|||||||
|
# ADR template |
||||||
|
|
||||||
|
Salin untuk keputusan arsitektur baru. |
||||||
@ -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) |
||||||
@ -0,0 +1,6 @@ |
|||||||
|
# Changelog — ArcGIS Enterprise |
||||||
|
|
||||||
|
## [0.1.0] - 2026-07-06 |
||||||
|
|
||||||
|
### Added |
||||||
|
- Struktur dokumentasi AI-Agent-Standards |
||||||
@ -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) | |
||||||
@ -0,0 +1,3 @@ |
|||||||
|
# Guides |
||||||
|
|
||||||
|
- [migration.md](./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) |
||||||
@ -0,0 +1,3 @@ |
|||||||
|
# Issues |
||||||
|
|
||||||
|
Belum ada issue terdokumentasi. |
||||||
@ -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 | |
||||||
@ -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. |
||||||
@ -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) |
||||||
@ -0,0 +1,9 @@ |
|||||||
|
# TODO — ArcGIS Enterprise |
||||||
|
|
||||||
|
## High |
||||||
|
|
||||||
|
- [ ] Verifikasi config live vs dokumentasi repo |
||||||
|
|
||||||
|
## Selesai |
||||||
|
|
||||||
|
- [x] Bootstrap AI-Agent-Standards 2026-07-06 |
||||||
@ -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 |
||||||
@ -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 |
||||||
@ -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) | |
||||||
@ -0,0 +1,3 @@ |
|||||||
|
# ADR template |
||||||
|
|
||||||
|
Salin untuk keputusan arsitektur baru. |
||||||
@ -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) |
||||||
@ -0,0 +1,6 @@ |
|||||||
|
# Changelog — Dockge |
||||||
|
|
||||||
|
## [1.5.0] - 2026-07-06 |
||||||
|
|
||||||
|
### Added |
||||||
|
- Struktur dokumentasi AI-Agent-Standards |
||||||
@ -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) | |
||||||
@ -0,0 +1,3 @@ |
|||||||
|
# Guides |
||||||
|
|
||||||
|
- [migration.md](./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. |
||||||
@ -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 | |
||||||
@ -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. |
||||||
@ -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) |
||||||
@ -0,0 +1,9 @@ |
|||||||
|
# TODO — Dockge |
||||||
|
|
||||||
|
## High |
||||||
|
|
||||||
|
- [ ] Verifikasi config live vs dokumentasi repo |
||||||
|
|
||||||
|
## Selesai |
||||||
|
|
||||||
|
- [x] Bootstrap AI-Agent-Standards 2026-07-06 |
||||||
@ -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 |
||||||
@ -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: |
## Apa ini? |
||||||
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) |
|
||||||
|
|
||||||
**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) |
## Lanjut kerja |
||||||
- 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` |
|
||||||
|
|
||||||
### PowerShell (Agent) |
``` |
||||||
- Module di `agent/lib/` — satu file per sensor (Get-CpuInfo.ps1, dll) |
1. AGENTS.md |
||||||
- Jangan hardcode credential di skrip |
2. docs/ai-session-summary.md |
||||||
- Hindari literal `$env:` di file `.ps1` yang di-serve Nginx (nginx potong respons) |
3. STOP |
||||||
- Test lokal dulu sebelum publish ke `agent.gisportal.id/install/` |
4. On-demand: docs/todo.md, docs/issues.md, .cursor/blueprint.md, docs/server.md |
||||||
|
|
||||||
### 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 |
|
||||||
``` |
``` |
||||||
|
|
||||||
- Update `agent/VERSION` + `agent/install/manifest.json` sebelum publish |
Detail kode: `.cursor/rules` equivalent via `.cursor/blueprint.md`, `docs/development.md`. |
||||||
- 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 |
|
||||||
|
|
||||||
--- |
|
||||||
|
|
||||||
## Batas Sistem (Non-goals) |
## Pointer cepat |
||||||
|
|
||||||
Jangan implement hal-hal berikut — sudah diputuskan di ADR/blueprint: |
| Butuh | Buka | |
||||||
- ❌ Engine monitoring time-series (pakai Zabbix) |
|-------|------| |
||||||
- ❌ NMS pengganti MikroTik/Proxmox tools |
| Priority | [docs/todo.md](./docs/todo.md) | |
||||||
- ❌ Duplikasi data GIS legacy dari SQL Server |
| Versi / deploy | [docs/version.md](./docs/version.md) | |
||||||
- ❌ Remote desktop / RMM agent |
| Server | [docs/server.md](./docs/server.md) | |
||||||
- ❌ Ticketing enterprise penuh (fase awal) |
| Schema DB | [docs/database.md](./docs/database.md) | |
||||||
|
| ADR | [docs/adr/](./docs/adr/) | |
||||||
|
|||||||
@ -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` |
||||||
@ -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/) |
||||||
@ -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 | |
||||||
@ -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) |
||||||
@ -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). |
||||||
@ -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) |
||||||
@ -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` |
||||||
@ -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) |
||||||
@ -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` |
||||||
Binary file not shown.
@ -1,15 +1,44 @@ |
|||||||
# Changelog — Mailcow |
# 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 |
||||||
@ -1,149 +1,88 @@ |
|||||||
# Context Index — Mailcow ⭐ AI Entry Point |
# Context Index — Mailcow |
||||||
|
|
||||||
> **Terakhir Diperbarui:** 2026-07-03 |
> Cold start: [../AGENTS.md](../AGENTS.md) → [ai-session-summary.md](./ai-session-summary.md) → **STOP** |
||||||
> **Fase Aktif:** Fase 1 — Mailcow live, transisi MX cPanel → sync 📧 |
|
||||||
|
|
||||||
**Sesi terakhir:** [docs/ai-session-summary.md](./ai-session-summary.md) |
|
||||||
|
|
||||||
--- |
--- |
||||||
|
|
||||||
## Filosofi |
## Zona A — Always-read pointers |
||||||
|
|
||||||
Proyek ini menerapkan **AI Native Development**: |
| Item | Value | |
||||||
- Repository = sumber kebenaran utama (Single Source of Truth) |
|------|-------| |
||||||
- AI tidak boleh mengandalkan riwayat percakapan |
| Nama | Mailcow | |
||||||
- Developer sering berpindah perangkat — konteks harus tersimpan di repo |
| Path monorepo | `Mailcow/` | |
||||||
- Implementasi tanpa dokumentasi = belum selesai |
| 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 |
### Dokumentasi inti |
||||||
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 |
|
||||||
|
|
||||||
--- |
|
||||||
|
|
||||||
## 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 | |
||||||
|
|
||||||
``` |
### Notes (domain) |
||||||
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 |
|
||||||
``` |
|
||||||
|
|
||||||
| Repo terkait | Entry point | Kapan baca | |
| Dokumen | Isi | |
||||||
|--------------|-------------|------------| |
|---------|-----| |
||||||
| **Zammad** | `Zammad/docs/context-index.md` | Channel email inbound/outbound | |
| [notes/gisportal-id-mail.md](./notes/gisportal-id-mail.md) | Domain `gisportal.id` — Mailcow murni, DNS Master Web | |
||||||
| **server-connection** | `server-connection/docs/context-index.md` | LDAP AD, nginx pattern | |
| [notes/hybrid-migration-cpanel-mailcow.md](./notes/hybrid-migration-cpanel-mailcow.md) | Jalur A/B hybrid geonet | |
||||||
| **mysupperapps_FE_PWA** | `docs/context-index.md` | Mail UI `/mail` (fase berikutnya) | |
| [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 |
| Repo | Entry | |
||||||
|
|------|-------| |
||||||
### `docs/` — Flat Files |
| Zammad | `Zammad/docs/context-index.md` | |
||||||
|
| server-connection | `server-connection/docs/context-index.md` | |
||||||
| File | Isi | Status | Baca Saat | |
| nginx | `nginx/docs/context-index.md` | |
||||||
|------|-----|--------|-----------| |
| Dockge | `Dockge/docs/context-index.md` | |
||||||
| `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 | |
|
||||||
|
|
||||||
--- |
--- |
||||||
|
|
||||||
## Quick Reference |
## Arsitektur singkat |
||||||
|
|
||||||
| Fungsi | URL / Path | |
``` |
||||||
|--------|------------| |
geonet.co.id → MX cPanel → fetchmail POP3 → Mailcow (hybrid, transport maps) |
||||||
| Mailcow UI (target) | `https://sync.geonet.co.id` | |
gisportal.id → MX mail.gisportal.id → 117.102.73.102 → Mailcow (murni) |
||||||
| Hostname mail | `sync.geonet.co.id` | |
├── Outlook IMAP :993 / SMTP :587 (sync.geonet.co.id) |
||||||
| Mailbox support (fase sync) | `support@sync.geonet.co.id` | |
└── Zammad IMAP (planned) |
||||||
| 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 |
|
||||||
``` |
``` |
||||||
|
|
||||||
> SSH ke server **wajib minta persetujuan user** sebelum dijalankan. |
| Fungsi | URL / Host | |
||||||
|
|--------|------------| |
||||||
--- |
| Mailcow UI | `https://sync.geonet.co.id` | |
||||||
|
| VM | `10.100.1.28` | |
||||||
## Status saat ini (2026-07-03) |
| IMAP/SMTP | `sync.geonet.co.id` :993 / :587 | |
||||||
|
| DNS gisportal | Master Web (`dns1.masterweb.com`) | |
||||||
| 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) |
|
||||||
|
|
||||||
--- |
--- |
||||||
|
|
||||||
## Aturan Utama AI |
## Aturan kritis AI |
||||||
|
|
||||||
1. Baca `docs/context-index.md` ini terlebih dahulu |
- No commit `.env`; update `.env.example` + `environment.md` |
||||||
2. **Jangan commit** `.env` — hanya update `.env.example` (placeholder) dan `docs/environment.md` |
- Deploy material → append `version.md` + `changelog.md` |
||||||
3. Integrasi Zammad → referensi `Zammad/docs/` — jangan duplikasi panjang |
- `support@` = authsource **ldap**; `admin@gisportal.id` = **mailcow** |
||||||
4. LDAP umum → referensi `server-connection/docs/environment.md` |
- Jangan masukkan user ke `Mail-Users` jika masih baca cPanel |
||||||
5. Setelah deploy → buat/update `docs/deployment.md` + `docs/project-status.md` |
- SSH wajib persetujuan user |
||||||
|
|||||||
@ -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 | |
||||||
@ -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 | |
||||||
@ -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`. |
||||||
@ -1,23 +1,19 @@ |
|||||||
# Issues — Mailcow |
# 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 | |
- `admin@gisportal.id` → user cPanel-only `@geonet.co.id`: cPanel reject (From vs SMTP auth) |
||||||
|-------|-------| |
- `rianjawa93@geonet.co.id` tidak ada di Mailcow |
||||||
| Status | Open | |
- Doc: [notes/gisportal-id-mail.md](./notes/gisportal-id-mail.md) |
||||||
| Severity | Medium | |
|
||||||
| Found | 2026-07-03 | |
|
||||||
|
|
||||||
**Workaround:** UPDATE _sogo_static_view FROM mailbox.password; restart sogo container. |
## Resolved |
||||||
|
|
||||||
--- |
- ISS-006 Internal mail cPanel user — transport Jalur B `rbsetiawan@` (2026-07-06) |
||||||
|
- ISS-003 SOGo Unauthorized (2026-07-03) |
||||||
## Resolved Issues |
- ISS-004 Gmail 550 relay (2026-07-03) |
||||||
|
- ISS-005 fetchmail SSL (2026-07-03) |
||||||
### ISS-003: SOGo Unauthorized — authsource mailcow + sync view (2026-07-03) |
- ISS-007 Outlook SMTP cert (2026-07-06) |
||||||
### ISS-004: Gmail 550 — relay sc138:587 (2026-07-03) |
|
||||||
### ISS-005: fetchmailrc parse — ssl after user, no sslcertck (2026-07-03) |
|
||||||
@ -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` |
||||||
@ -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 |
||||||
@ -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). |
||||||
@ -1,47 +1,39 @@ |
|||||||
# TODO — Mailcow |
# TODO — Mailcow |
||||||
|
|
||||||
> Last updated: 2026-07-03 |
> Last updated: 2026-07-06 |
||||||
|
|
||||||
--- |
--- |
||||||
|
|
||||||
## High Priority |
## High Priority |
||||||
|
|
||||||
- [ ] Publish DKIM TXT dkim._domainkey.geonet.co.id (key dari Mailcow API) |
- [ ] **DKIM `gisportal.id`** publish TXT dari Mailcow Admin → Master Web |
||||||
- [ ] Update SPF geonet.co.id — include IP 117.102.73.102 atau relay sementara |
- [ ] Verifikasi terima/kirim `admin@gisportal.id` (Gmail ↔ SOGo) setelah DKIM |
||||||
- [ ] Zammad channel email → IMAP/SMTP Mailcow 10.100.1.28 (ganti cPanel) |
- [ ] Publish DKIM + SPF `geonet.co.id` |
||||||
|
- [ ] Zammad channel email → IMAP/SMTP Mailcow `10.100.1.28` |
||||||
|
|
||||||
--- |
--- |
||||||
|
|
||||||
## Medium Priority |
## Medium Priority |
||||||
|
|
||||||
- [ ] PTR/rDNS 117.102.73.102 → sync.geonet.co.id |
- [ ] PTR/rDNS `117.102.73.102` → `sync.geonet.co.id` |
||||||
- [ ] Buat scripts/install-relay-cpanel.sh (mirror fetchmail installer) |
- [ ] Script `install-relay-cpanel.sh` |
||||||
- [ ] Automasi sync _sogo_static_view setelah password mailbox mailcow berubah |
- [ ] Auto-sync `_sogo_static_view` setelah ganti password |
||||||
- [ ] Monitoring fetchmail (Uptime Kuma atau alert log) |
- [ ] Hapus relayhost id=2 typo di Mailcow Admin (jika masih ada) |
||||||
|
|
||||||
--- |
--- |
||||||
|
|
||||||
## Low Priority |
## Low Priority |
||||||
|
|
||||||
- [ ] fetchmail entry untuk mailbox tambahan (info@, dll.) |
- [ ] MX cutover `geonet.co.id` → `sync.geonet.co.id` |
||||||
- [ ] LDAP user lain di Mail-Users — provisioning + Outlook guide |
- [ ] Matikan fetchmail + relay cPanel setelah cutover |
||||||
- [ ] Domain sekunder gegeo.my.id |
- [ ] Transport map `rianjawa93@` jika tetap di cPanel |
||||||
- [ ] MX cutover ke sync.geonet.co.id (setelah 2–4 minggu stabil) |
|
||||||
- [ ] Matikan fetchmail + relay cPanel pasca cutover |
|
||||||
|
|
||||||
--- |
--- |
||||||
|
|
||||||
## Selesai (Sesi 2026-07-03) |
## Selesai (Sesi Ini) |
||||||
|
|
||||||
- [x] fetchmail POP3 drain support@ + timer 2 menit |
- [x] Jalur B `rbsetiawan@`: transport map + verified `support@` → cPanel |
||||||
- [x] Relay outbound cPanel :587 untuk geonet.co.id |
- [x] Domain `gisportal.id` + mailbox `admin@gisportal.id` + SOGo |
||||||
- [x] SOGo login + kirim/terima email verified |
- [x] Forwarding hosts whitelist inbound gisportal |
||||||
- [x] scripts/install-fetchmail-support.sh |
- [x] SPF `gisportal.id`: `v=spf1 ip4:117.102.73.102 -all` (Master Web, propagasi OK) |
||||||
- [x] Dokumentasi handover sesi |
- [x] Scripts + docs dual-domain (`gisportal-id-mail.md`, hybrid migration) |
||||||
|
|
||||||
--- |
|
||||||
|
|
||||||
## Technical Debt |
|
||||||
|
|
||||||
- [ ] support@ service account vs LDAP — dokumentasikan keputusan |
|
||||||
- [ ] context-index diagram IP — align ke .28 |
|
||||||
|
|||||||
@ -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/`) |
||||||
@ -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 '<key>(geonet|gisportal|gegeo)' /var/lib/sogo/GNUstep/Defaults/sogod.plist || \ |
||||||
|
docker exec mailcowdockerized-sogo-mailcow-1 grep '<key>.*\.id</key>' /var/lib/sogo/GNUstep/Defaults/sogod.plist |
||||||
|
|
||||||
|
echo "" |
||||||
|
echo "DONE. Login SOGo with Mailcow mailbox password (NOT AD password for authsource=mailcow)." |
||||||
@ -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" |
||||||
@ -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" |
||||||
@ -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)" |
||||||
@ -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" |
||||||
@ -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 |
||||||
@ -0,0 +1,7 @@ |
|||||||
|
# Local secrets — never commit |
||||||
|
.env |
||||||
|
.env.* |
||||||
|
!.env.example |
||||||
|
|
||||||
|
# Optional: full export with show-sensitive (if ever used) |
||||||
|
backups/*-sensitive.rsc |
||||||
@ -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` | |
||||||
@ -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) |
||||||
@ -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 |
||||||
|
``` |
||||||
@ -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 |
||||||
@ -0,0 +1,3 @@ |
|||||||
|
# ADR Template |
||||||
|
|
||||||
|
Salin untuk keputusan baru. Contoh: [ADR-0001-hybrid-dual-wan.md](./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` |
||||||
@ -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` | |
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue