D
Engineering

Conventions

Konvensi kode Konco — Service Layer pattern (app/Services/), thin controllers, UUID + WithAuthor trait wajib di model baru, bahasa Indonesia untuk kode/UI/komentar, Livewire untuk real-time, observer pattern, helper autoload.

Konco mengikuti sejumlah konvensi kode yang kuat. Bagian ini wajib dibaca engineer baru sebelum menulis kode pertama — banyak pola tidak tertulis di dokumentasi framework tapi konsisten di seluruh codebase.

Service Layer pattern

Business logic kompleks wajib di app/Services/, bukan di controller. Controller tetap thin — hanya validasi, delegasi ke service, dan return response.

Services yang ada

ServiceLokasiTanggung jawab
OrderServiceapp/Services/OrderService.phpProses order: subscribe & topup
PaymentServiceapp/Services/PaymentService.phpIntegrasi payment gateway
MonitpayServiceapp/Services/MonitpayService.phpSpesifik MonitPay integration
AdminRequestServiceapp/Services/AdminRequestService.phpWorkflow approval admin request
TeamServiceapp/Services/TeamService.phpManajemen tim multi-user
PermissionServiceapp/Services/PermissionService.phpRole & permission handling

Pola controller → service

php
// Controller — thin
class SubscribeController extends Controller
{
    public function store(Request $request, OrderService $orderService)
    {
        $validated = $request->validate([...]);
        $order = $orderService->createSubscribe($validated);
        return redirect()->route('member.subscribe.index');
    }
}

Model traits wajib

Setiap model baru wajib memakai kombinasi trait ini:

TraitFungsi
App\Traits\UUIDAuto-generate UUIDv4 primary key saat creating
App\Traits\WithAuthorAuto-isi created_by / updated_by dari Auth::id() saat saving
App\Traits\DateTimeTrait(opsional) Utility date/time formatting

Blueprint model baru

php
<?php

namespace App\Models;

use App\Traits\UUID;
use App\Traits\WithAuthor;
use Illuminate\Database\Eloquent\Model;

class YourModel extends Model
&#123;
    use UUID, WithAuthor;

    protected $keyType = 'string';
    public $incrementing = false;

    protected $fillable = [
        'field1',
        'field2',
    ];

    // ...
&#125;

Migration blueprint

php
Schema::create('your_models', function (Blueprint $table) &#123;
    $table->uuid('id')->primary();
    $table->string('field1');
    $table->uuid('created_by')->nullable();
    $table->uuid('updated_by')->nullable();
    $table->timestamps();
&#125;);

Bahasa Indonesia

AreaBahasaCatatan
Komentar kodeIndonesiaBukan Inggris
Nama field databaseIndonesiae.g. expired, is_active, created_by (pengecualian: stock_ads_account_id)
Label UIIndonesiae.g. “Sedang diproses”, “Akun Aktif”
Nama class/methodInggrisKonvensi PSR-12
php
// Benar
// cek apakah akun sudah di-share
if ($account->isShared()) &#123; ... &#125;

// Salah
// check if account is shared
if ($account->isShared()) &#123; ... &#125;

PSR-12

AspekKonvensi
StylingPSR-12
Linterlaravel/pint (dev dependency) — jalankan ./vendor/bin/pint
Formatting4 spaces indent, opening brace same line untuk class/method, next line untuk control structures

Livewire 2.x

Real-time UI memakai Livewire — components di app/Http/Livewire/, views di resources/views/livewire/.

Struktur Livewire Konco

text
app/Http/Livewire/
├── Admin/            # Livewire admin portal
│   ├── BusinessManagerSelectWire.php
│   └── ...
└── Member/           # Livewire member portal
    ├── AdsAccountMemberWire.php
    ├── AdsBalanceIndexWire.php
    ├── AdsManagerIndexWire.php
    ├── SubscribeAdsList.php
    ├── WithdrawIndexWire.php
    └── ...

Pola Livewire

php
class AdsAccountMemberWire extends Component
&#123;
    public $search;
    public $filterStatus;

    public function render()
    &#123;
        $accounts = AdsAccount::query()
            ->where('member_bm_id', auth()->user()->member->id)
            ->when($this->search, fn($q, $v) => $q->where('name', 'like', "%&#123;$v&#125;%"))
            ->when($this->filterStatus, fn($q, $v) => $q->where('status', $v))
            ->paginate(10);

        return view('livewire.member.ads-account-member-wire', compact('accounts'));
    &#125;
&#125;

Observer pattern

Model observer di app/Observers/:

ObserverDi-observe modelFungsi
AdminRequestObserverAdminRequestTrack lifecycle admin request (created, updated, status change)

Registrasi observer

Observer di-register di App\Providers\EventServiceProvider:

php
protected $observers = [
    AdminRequest::class => [AdminRequestObserver::class],
];

Events & broadcasting

Events di app/Events/:

EventTriggerChannel
AdminRequestCreatedAdmin request baru dibuatPrivate channel admin
TicketMessageCreatedPesan tiket dikirimPrivate channel tiket
TicketStatusUpdatedStatus tiket berubahPrivate channel tiket

Broadcasting via Laravel Reverb (WebSocket) — config di config/reverb.php. Frontend memakai Laravel Echo + Pusher JS (kompatibel Reverb).

Helper functions

Helper global di-auto-load via composer.json autoload.files:

FileIsi
app/helper/helpers.phpUtility umum — date formatting, text limiting, decode(), send_email(), send_report()
app/helper/role_helper.phpRole & permission utilities
app/helper/asset_version.phpAsset versioning untuk cache busting
php
// composer.json
"autoload": &#123;
    "files": [
        "app/helper/helpers.php",
        "app/helper/role_helper.php",
        "app/helper/asset_version.php"
    ]
&#125;

Helper tersedia global di seluruh aplikasi — tidak perlu use atau import.

Middleware custom

MiddlewareAliasFungsi
TwoFactorAuthentication2faEnforce 2FA verification
SandboxAccessMiddlewaresandboxRestrict route ke environment non-production
EnsureUserHasTeamMiddleware—Validasi team membership
RedirectIfCannotAccessDashboard—Dashboard access control
LanguageMiddleware—Multi-language switching
cekAuth:member—Custom guard check untuk member

Registrasi di app/Http/Kernel.php $routeMiddleware.

Config custom

FileIsi
config/facebook.phpFacebook API credentials lokal (web app — meski Graph API di API engine)
config/monitpay.phpMonitPay payment gateway config
config/myconfig.phpApplication-specific settings
config/google2fa.php2FA config
config/reverb.phpWebSocket broadcasting config
config/passport.phpPassport OAuth2 config

Routing convention

AreaFilePrefixGuard
Adminroutes/_admin.php/adminauth:admin, 2fa
Memberroutes/_member.php/membercekAuth:member, permission:*
Profileroutes/_profile.php(included in admin/member)auth
Public + authroutes/web.php/(mixed)
API/webhookroutes/api.php/api(mixed)
Broadcast channelsroutes/channels.php—(broadcast auth)
Consoleroutes/console.php——

Naming convention

php
// Route name pattern: <scope>.<resource>.<action>
Route::get('/', [UserController::class, 'index'])->name('admin.user.index');
Route::post('/', [UserController::class, 'store'])->name('admin.user.store');
Route::get('/&#123;id&#125;/edit', [UserController::class, 'edit'])->name('admin.user.edit');

Langkah berikutnya