yongol — Lunas Kapal SaaS yang Dikodekan AI Gambar: Dihasilkan AI

Jika AI terus menimpa kode Anda, jika vibe coding runtuh di 200 endpoint, jika Anda ingin mengalihkan beban kerja AI dari kode ke spesifikasi — yongol adalah lunas kapal itu.

Endpoint ke-200

Kamu membangun SaaS dengan vibe coding. Awalnya cepat. 5 tabel, 12 endpoint — dua puluh menit dan berjalan.

Tapi melewati 50 endpoint, hal aneh terjadi. AI menghasilkan pola hari ini yang bertentangan dengan kemarin. Melewati 100, fitur yang ada diam-diam rusak. Melewati 200, menambahkan satu fitur memakan biaya 10 kali lipat dari sepuluh pertama.

Laporan DORA 2025 membuktikan ini secara empiris — alat AI meningkatkan throughput 2-18%, tetapi secara bersamaan meningkatkan tingkat kegagalan perubahan dan pengerjaan ulang[1]. AI adalah “cermin dan pengali” yang memperkuat kelemahan proses yang ada.

Bukan karena modelnya bodoh.


Keputusan dan implementasi

Tiga hal terjalin dalam kode sumber:

  • Keputusan pengguna — kolom ini BIGINT, endpoint ini hanya untuk pemilik, paginasi menggunakan cursor.
  • Logika bisnis — kebijakan harga, alur kerja, aturan siklus hidup.
  • Detail implementasi — nama variabel, urutan pemanggilan library, pembungkusan error.

Ketika AI membaca kode ini, ia tidak bisa membedakan baris mana yang keputusan dan mana yang detail. Jadi ketika “merefaktor” atau “membersihkan”, ia diam-diam menimpa keputusan yang disangka detail. Pengguna baru menyadari setelah perilaku sudah salah. Pada 1972, Parnas berkata “sembunyikan keputusan desain yang mungkin berubah di balik antarmuka”[2] — dia berbicara kepada manusia. Tapi sekarang AI juga mengedit kode, kecuali pembedaan antara keputusan dan detail ada di dalam medium itu sendiri, tidak ada siapa pun — manusia maupun model — yang bisa mempertahankannya.

Inilah mengapa vibe coding runtuh di 200 endpoint. Model yang lebih besar tidak memperbaikinya. Medium — kode mentah — sama sekali tidak melestarikan keputusan. Setiap model akhirnya menabrak dinding yang sama.


Lunas kapal

Lunas adalah tulang pertama yang diletakkan saat membangun kapal. Ia menahan berat lambung, mencegah oleng, dan setiap struktur lain dibangun di atasnya. Kapal yang dibangun tanpa lunas mengapung di air tenang tapi melengkung saat ombak datang.

SaaS yang dibangun dengan vibe coding sama saja. Mengapung saat kecil. Melengkung saat membesar.

yongol adalah lunas kapal SaaS yang dikodekan AI.

Harness with reins — bukan model yang lebih besar, tapi kendali yang lebih presisi. Validator deterministik menilai setiap artefak, ratchet memaksa kemajuan, dan mesin yang memutuskan apakah pekerjaan selesai.


Pindahkan keputusan keluar dari kode

Inti yongol sederhana. Pisahkan keputusan dari kode.

Sepuluh spesifikasi deklaratif (SSOT) masing-masing menangani satu tanggung jawab:

SSOTTanggung Jawab
features.yamlKatalog fitur — apa yang akan dibangun
manifest.yamlKonfigurasi proyek — autentikasi, middleware, infrastruktur
OpenAPIKontrak API — rute, parameter, respons
SQL DDL + sqlcModel data — tabel, kolom, constraint, query
SSaCAlur layanan — urutan keputusan di dalam endpoint
RegoOtorisasi — siapa boleh melakukan apa
Mermaid stateDiagramTransisi status — siklus hidup entitas
FuncSpecFungsi kustom — logika yang tidak bisa diekspresikan sebagai CRUD
HurlSkenario pengujian — trikotomi smoke, scenario, invariant
STMLFrontend — Semantic Template Markup Language (HTML berbasis atribut data-*)

Delapan dari sepuluh adalah standar industri (OpenAPI, SQL, sqlc, Rego, Mermaid, Hurl, YAML). Hanya SSaC dan STML yang DSL buatan yongol. Apa yang harus dipelajari AI dari nol diminimalkan.

Setiap SSOT berisi hanya keputusan. Tanpa detail implementasi. AI mengedit SSOT; yongol generate merender kode darinya. Keputusan hidup permanen di SSOT; kode adalah proyeksi sekali pakai.


Memaksa konsistensi

Keputusan kini tersebar di sepuluh file, jadi kontradiksi bisa muncul. DDL bilang BIGINT tapi OpenAPI bilang string? SSaC mendeklarasikan @auth tapi Rego tidak punya aturan yang cocok? Diagram status punya transisi tapi SSaC tidak punya fungsi yang sesuai?

SSOT yang berkontradiksi adalah keputusan yang tercemar. Sebersih apa pun kodenya, jika keputusan bertentangan, perilaku akan menyimpang.

yongol validate menangkap ini.

✓ manifest        ✓ openapi_ddl       ✓ ssac_rego
✓ openapi         ✓ openapi_ssac      ✓ ssac_authz
✓ ddl             ✓ hurl_openapi      ✓ ssac_sqlc
✓ query           ✓ hurl_statemachine ✓ ddl_statemachine
✓ ssac            ✓ hurl_manifest     ✓ ddl_rego
✓ statemachine    ✓ openapi_manifest  ✓ rego_manifest
✓ rego            ✓ ssac_ddl          ✓ stml_openapi
✓ hurl            ✓ ssac_statemachine
✓ funcspec        ✓ ssac_func

0 errors, 0 warnings

Pertama memvalidasi setiap SSOT secara individual, lalu menjalankan pemeriksaan silang antar lapisan. ~287 aturan memeriksa setiap referensi simbolik di antara sepuluh SSOT. Jika ada satu kontradiksi, kompilasi ditolak. Tinjauan literatur sistematis Torres et al.[3] mencatat bahwa sebagian besar alat manajemen model hanya menangani konsistensi dalam satu model, meninggalkan verifikasi silang antar model heterogen sebagai masalah terbuka — yongol validate mengisi tepat celah itu.

AI menulis dengan bebas. Keluar dari rel, validate langsung menangkap. Kebebasan di atas rel.


yongol next — Perintah ratchet

Sementara yongol validate menampilkan semua error sekaligus, yongol next menampilkan error satu per satu. Ini adalah ratchet.

$ yongol next specs/

[ERROR] DDL-003: users.id must be BIGINT, got INT
  file: specs/db/users.sql:2
  ▶ Fix this error. Then run `yongol next specs/`.

Satu-satunya instruksi yang dibutuhkan agen AI adalah satu kalimat: “Jalankan yongol next specs/ dan perbaiki error sampai 0.”

Perbaiki error, yang berikutnya muncul. Lewati semua dan berhenti:

$ yongol next specs/

✓ All validations passed. 0 errors.

Agen tidak menyatakan “saya selesai”. Mesin yang memutuskan “masih tersisa” atau “semua lolos”. Agen tidak punya otoritas atas penilaian terminasi.


Pembuatan proyek dan manajemen fitur

yongol init

Membuat scaffolding SSOT secara otomatis dari features.yaml.

yongol init Myapp features.yaml "My workflow automation SaaS"
cd Myapp && yongol validate specs     # 0 errors

Manifest, stub operationId OpenAPI, file stub SSaC, aturan otorisasi Rego, tes smoke Hurl, dan konfigurasi sqlc dihasilkan sekaligus. Proyek dimulai dalam keadaan lolos yongol validate sejak awal.

yongol features add / remove

Menambah atau menghapus fitur:

yongol features add new_features.yaml         # Membuat stub SSaC untuk operationId baru
yongol features remove ExportWorkflow --yes    # Menghapus operationId + stub SSaC

yongol import

Membuat paket klien Go dari spesifikasi OpenAPI eksternal (Stripe, GitHub, dll.):

yongol import https://api.stripe.com/openapi.yaml ./external/

Memanggil fungsi yang dihasilkan di SSaC dengan @call <pkg>.<Func>({...}).


operationId adalah batu kunci

Bagaimana mengikat sepuluh lapisan bersama? Dengan satu identifier PascalCase.

Masukkan operationId ExecuteWorkflow:

── Feature Chain: ExecuteWorkflow ──

  OpenAPI    api/openapi.yaml                POST /workflows/{id}/execute
  SSaC       service/workflow/execute_workflow.ssac   @get @empty @auth @state @call @publish @response
  DDL        db/workflows.sql                CREATE TABLE workflows
  DDL        db/execution_logs.sql           CREATE TABLE execution_logs
  Rego       policy/authz.rego               resource: workflow
  StateDiag  states/workflow.md              diagram: workflow → ExecuteWorkflow
  FuncSpec   func/billing/check_credits.go   @func billing.CheckCredits
  FuncSpec   func/billing/deduct_credit.go   @func billing.DeductCredit
  FuncSpec   func/worker/process_actions.go  @func worker.ProcessActions
  FuncSpec   func/webhook/deliver.go         @func webhook.Deliver
  Hurl       tests/scenario-happy-path.hurl  scenario: scenario-happy-path.hurl

Dari spesifikasi API hingga skema database, dari kebijakan otorisasi hingga transisi status, dari implementasi fungsi hingga skenario pengujian — topologi lengkap satu fitur dalam satu layar. Puluhan grep diganti satu perintah.

operationId adalah batu kunci karena dalam aplikasi full-stack, unit sebuah fitur adalah endpoint API. Pengguna menekan tombol, API dipanggil, dan API itu memotong setiap lapisan lain. Satu nama merantai sepuluh lapisan secara fisik.


SSaC — Mengapa DSL kustom

Delapan dari 10 SSOT yongol adalah standar industri. Hanya SSaC (Service Sequences as Code) dan STML yang dibuat yongol. SSaC menangkap keputusan alur layanan.

Celah yang diisi SSaC. Lihat spektrum alat deklaratif: di satu ujung ada standar kontrak (OpenAPI, SQL, Rego) — mendeklarasikan apa tapi tidak dalam urutan apa. Di ujung lain ada runtime workflow (Temporal, Inngest, Restate) — itu adalah kode. Keputusan dan detail implementasi bergabung kembali dalam file yang sama. SSaC duduk di celah di antaranya: “di dalam satu endpoint, apa yang terjadi, dalam urutan apa, dengan penjaga apa.”

SSaC memiliki total 16 anotasi. Bisa dipelajari dari manual satu halaman.

Daftar lengkap anotasi SSaC

AnotasiPeranFormat
@getBaca DBType var = Model.Method({args})
@postPembuatan barisType var = Model.Method({args})
@putPembaruan baris (tanpa return)Model.Method({args})
@deletePenghapusan barisModel.Method({args})
@emptyPenjaga nil → 404var "message" [STATUS]
@existsPenjaga not-nil → 409var "message" [STATUS]
@authPemeriksaan otorisasi"action" "resource" {inputs} "message" [STATUS]
@stateTransisi mesin statusdiagram {inputs} "transition" "message" [STATUS]
@callPemanggilan fungsi[Type var =] pkg.Func({args})
@evalPenjaga predikat (true → error)pkg.Func({args}) "message" STATUS
@publishPublikasi ke antrian"topic" {payload}
@subscribeFungsi pemicu antrian"topic"
@verify-passwordLogin (aman terhadap timing)Model.col=source Model.hash vs source -> var STATUS "msg"
@responseReturn JSON{ field: var, ... } atau var
@no-paginationPengecualian aturan paginasi(level fungsi)
@state-neutralPengecualian aturan mesin status(level fungsi)

Contoh SSaC — AcceptProposal

Otorisasi + mesin status ganda + escrow + antrian:

package service

import "github.com/org/project/internal/billing"

// @get Proposal p = Proposal.FindByID({ID: request.id})
// @empty p "Proposal not found" 404
// @get Gig gig = Gig.FindByID({ID: p.GigID})
// @empty gig "Gig not found" 404
// @auth "AcceptProposal" "gig" {ResourceID: request.id} "Forbidden" 403
// @state proposal {status: p.Status} "AcceptProposal" "Cannot accept" 409
// @state gig {status: gig.Status} "AcceptProposal" "Cannot accept on gig" 409
// @put Proposal.UpdateStatus({ID: p.ID, Status: "accepted"})
// @put Gig.AssignFreelancer({ID: gig.ID, FreelancerID: p.FreelancerID, Status: "in_progress"})
// @call billing.HoldEscrowResponse escrow = billing.HoldEscrow({GigID: gig.ID, Amount: gig.Budget})
// @publish "proposal.accepted" {GigID: gig.ID, FreelancerID: p.FreelancerID}
// @get Proposal updated = Proposal.FindByID({ID: p.ID})
// @response { proposal: updated }
func AcceptProposal() {}

16 baris. 10 anotasi. Dua mesin status, otorisasi, escrow, event antrian, respons — setiap keputusan terlihat, setiap detail absen.


Benchmark: ZenFlow

ZenFlow — SaaS otomasi workflow multi-tenant.

TahapDeskripsiWaktuKumulatif
Build awal10 endpoint, 6 tabel, auth, mesin status13 mnt13 mnt
+ Versioningklon workflow, daftar versi6 mnt19 mnt
+ Webhookswebhook CRUD, backend antrian6 mnt25 mnt
+ Marketplace templatepaginasi cursor, klon lintas organisasi3 mnt28 mnt
+ Lampiran filelaporan eksekusi, backend file4 mnt32 mnt
+ Penjadwalanpenjadwalan cron, backend sesi6 mnt38 mnt
+ Log auditpaginasi offset, backend cache3 mnt41 mnt
+ Dashboardjoin relasi, tipe respons func7 mnt48 mnt
+ Operasi batchinsert massal jsonb14 mnt62 mnt
+ API eksternalfunc geocoding, penambahan kolom3 mnt65 mnt
+ Update kondisionalpola sentinel, penugasan otomatis4 mnt69 mnt

Final: 32 endpoint, 14 tabel, 47 request Hurl. 11/11 tahap lolos.

Menambah fitur tidak pernah melambat. Tes yang ada tidak pernah rusak. Dinding 200 endpoint tidak ada.

Benchmark Opus 4.7 — 32 endpoint, 14 tabel, 47 request Hurl, ~69 mnt. Benchmark Sonnet 4.6 — 32 endpoint, 9 tabel, 37 request Hurl, ~43 mnt.


yongol agent

LLM secara otomatis memperbaiki file SSOT melalui loop validate-fix.

yongol agent specs/ --model ollama:gemma4:e4b --max-rounds 20

Error validate di-feedback ke LLM, LLM memperbaikinya, dan validasi dijalankan lagi. Loop berulang sampai 0 error. Bekerja bahkan dengan model lokal 4.5B (Gemma4).

Backend yang didukung: ollama (lokal), xai (Grok), gemini.


Bisakah mengedit kode yang dihasilkan

Bisa. yongol generate melestarikan edit pengguna saat dijalankan ulang:

  • Setiap file yang dihasilkan mendapat anotasi //yg:checked llm=yongol-gen hash=<8hex>.
  • Jika hash berbeda, file ditandai sebagai preserved dan dilewati pada generate berikutnya.
  • yongol status menampilkan file yang preserved dan drift kontrak (error PRV-01/PRV-02).
  • Untuk mencatat niat, tambahkan //yg:preserve reason="..." (opsional). Untuk membatalkan preserve, hapus file.

Fungsi dan model bawaan

Fungsi bawaan (dipanggil via @call di SSaC)

PaketFungsiDeskripsi
authhashPassword, verifyPasswordHash/verifikasi bcrypt
authissueToken, verifyToken, refreshTokenToken JWT
authgenerateResetTokenReset kata sandi
cryptoencrypt, decryptAES-256-GCM
cryptogenerateOTP, verifyOTPTOTP
storageuploadFile, deleteFile, presignURLS3
mailsendEmail, sendTemplateEmailSMTP
textgenerateSlug, sanitizeHTML, truncateTextPemrosesan teks
imageogImage, thumbnailPembuatan gambar

Model bawaan (dikonfigurasi via manifest.yaml)

PaketAntarmukaBackendPenggunaan SSaC
sessionSessionModel (Set/Get/Delete + TTL)PostgreSQL, Memorysession.Session.Get({key: ...})
cacheCacheModel (Set/Get/Delete + TTL)PostgreSQL, Memorycache.Cache.Set({key: ..., value: ..., ttl: ...})
fileFileModel (Upload/Download/Delete)S3, LocalFilefile.File.Upload({key: ..., body: ...})
queuesingleton Pub/Sub (Publish/Subscribe)PostgreSQL, Memory@publish "topic" {payload}

Pembuatan migrasi DDL otomatis

yongol generate mendeteksi perubahan DDL dan secara otomatis menghasilkan file migrasi.

specs/db/
└── users.sql                         # SSOT — edit di sini

artifacts/db/
├── .latest_schema.sql                # Snapshot baseline
└── migrations/
    ├── 0001_initial.up.sql
    ├── 0001_initial.down.sql
    ├── 0002_add_users_email.up.sql
    └── 0002_add_users_email.down.sql

Perubahan ambigu (rename kolom, type casting, backfill NOT NULL) disambiguasi dengan hint komentar DDL (-- @rename, -- @cast, -- @backfill, -- @data_migration, -- @allow_destructive). Enam aturan (MIG-001 hingga MIG-006) menjaga perubahan berbahaya. Penerapan aktual di database didelegasikan ke alat standar seperti golang-migrate, flyway, dll.


Mengapa model yang lebih besar bukan jawabannya

“GPT-6 akan menyelesaikan ini.”

Tidak akan. Masalahnya bukan kecerdasan model — tapi medium.

Kode sebagai medium tidak membedakan keputusan dari implementasi. Model apa pun yang membaca kode melihat teks di mana keputusan dan detail terjalin. Sepintar apa pun modelnya, jika medium tidak menyediakan pembedaan, model tidak bisa membedakan.

yongol mengubah medium. Ia memindahkan apa yang diedit AI dari kode ke spesifikasi deklaratif. Karena spesifikasi hanya berisi keputusan tanpa detail implementasi, AI tidak pernah bisa mengira keputusan sebagai detail. Kelangsungan keputusan menjadi independen dari ukuran model.

LLM kecil yang hanya mengedit SSOT, dengan validate memberikan feedback presisi pada setiap kesalahan, bisa mempertahankan integritas keputusan yang sama dengan model yang jauh lebih besar yang mengedit kode mentah. yongol menjembatani kesenjangan itu.


Tes runtime

Tes Hurl semuanya ditulis pengguna. Tulis di specs/tests/ dan yongol generate memirrorkan ke artifacts/tests/. Saat validasi, aturan XOH-01 hingga XOH-09 memeriksa silang Hurl terhadap OpenAPI, mesin status, dan manifest.auth.

hurl --test --variable host=http://localhost:8080 artifacts/my-project/tests/*.hurl

Tiga kategori:

  • smoke.hurl — Tes smoke endpoint
  • scenario-*.hurl — Tes skenario bisnis
  • invariant-*.hurl — Tes invarian lintas endpoint

Status saat ini

Pembuatan backend Go+Gin: Beta — berfungsi end-to-end. Pembuatan frontend React: Alpha (sedang dikerjakan).


Mulai

Metode 1: Instal Skill (Direkomendasikan)

npx skills add park-jun-woo/yongol

Instal skill yongol ke agen AI kamu (Claude Code, Cursor, Copilot, dan lainnya). Agen mempelajari alur kerja saat instalasi.

/yongol Bangun SaaS todo multi-tenant dengan auth dan CRUD.

Metode 2: Instalasi langsung

Membutuhkan Go 1.25+ dan gcc (dependensi cgo: pg_query_go menghubungkan libpg_query untuk parsing DDL).

git clone https://github.com/park-jun-woo/yongol && cd yongol
make install
yongol validate examples/zenflow

0 errors, 0 warnings.

Arahkan AI ke spesifikasi ini dan suruh tambahkan fitur. validate memasang rel; AI berlari di atasnya. Tidak ada dinding.


Referensi

  1. Google DORA Team. DORA State of AI-Assisted Software Development 2025. Google Cloud, 2025. dora.dev/dora-report-2025
  2. David L. Parnas. “On the Criteria to Be Used in Decomposing Systems into Modules.” Communications of the ACM 15(12): 1053-1058, 1972. doi:10.1145/361598.361623
  3. Weslley Torres, Mark G.J. van den Brand, Alexander Serebrenik. “A Systematic Literature Review of Cross-Domain Model Consistency Checking by Model Management Tools.” Software and Systems Modeling 20(3): 897-916, 2021. doi:10.1007/s10270-020-00834-1
  4. Deepak Babu Piskala. “Spec-Driven Development: From Code to Contract in the Age of AI Coding Assistants.” arXiv:2602.00180, January 2026. arxiv.org/abs/2602.00180
  5. Ehsani et al. “When AI Code Doesn’t Stick: An Empirical Study on Reverted Changes Introduced by AI Coding Agents.” MSR 2026 Mining Challenge, April 2026. 2026.msrconf.org
  6. Anton Jansen, Jan Bosch. “Software Architecture as a Set of Architectural Design Decisions.” EWSA 2005, LNCS 3527, Springer, 2005. semanticscholar.org
  7. Marco Brambilla, Jordi Cabot, Manuel Wimmer. Model-Driven Software Engineering in Practice. 2nd ed., Springer, 2017. doi:10.1007/978-3-031-02546-4
  8. GitClear. AI Copilot Code Quality 2025. February 2025. gitclear.com

Artikel terkait

Kode: github.com/park-jun-woo/yongol


Riwayat perubahan

TanggalPerubahan
2026-05-18Publikasi awal
2026-05-19Ditambahkan benchmark Opus. Diperbarui 10 SSOT
2026-05-21Sinkronisasi README: pembaruan benchmark (Opus 32ep/14tbl/47hurl/69min, Sonnet 32ep/9tbl/37hurl/43min), ditambahkan pernyataan “Harness with reins”, ditambahkan contoh SSaC (AcceptProposal), ditambahkan perintah yongol agent, ditambahkan sistem Preserve, ditambahkan daftar fungsi/model bawaan, ditambahkan pembuatan migrasi DDL otomatis, ditambahkan deskripsi STML, ditambahkan tautan artikel ifeval-ratchet
2026-05-26Sinkronisasi v0.6.10: ditambahkan perintah ratchet yongol next, ditambahkan yongol init/features add/features remove pembuatan dan manajemen proyek, ditambahkan yongol import impor OpenAPI eksternal, ditambahkan daftar lengkap anotasi SSaC (16) (@eval, @subscribe, @verify-password, @no-pagination, @state-neutral), trikotomi tes Hurl (smoke/scenario/invariant), bagian tes runtime, detail Preserve (kode error PRV), ekspansi hint migrasi DDL (@data_migration, @allow_destructive, aturan MIG), status saat ini (Go+Gin Beta, React Alpha), instalasi dibagi menjadi 2 metode