Skip to content

Entity ​

<!-- generated:meta -->

Grupdata
Planeresource
Spec structEntitySpec

<!-- /generated:meta -->

Kapan Memakai ​

kind: Entity adalah kind terpenting FormSpec — merepresentasikan data bisnis stateful yang dipersist. 95% kasus pembuatan aplikasi jawabannya Entity. Needing kind lain berarti memperluas framework, bukan membangun app.

Pilih karakteristik yang tepat (mutually exclusive — formspec apply menolak lebih dari satu):

KarakteristikArtiWajib
masterData referensi stabil (Customer, Product)Boleh punya lifecycle atau tidak
transactionAppend-heavy, time-partitioned (Invoice, Journal Entry)Wajib field transaction_date
referenceSeed data read-only (Provinsi, Tarif Pajak)—
summaryProjeksi terkelola sistem (GL Balance)CUD permanen nonaktif via API

Kapan TIDAK pakai Entity:

  • Komputasi tanpa state → kind: Service
  • Hanya butuh UI override → tambah kind: Form / kind: Table (Entity tetap ada)

Sumber kontrak: docs/spec/backend/01-core-basic.md §1.

Contoh Manifest ​

yaml
apiVersion: formspec.dev/v1
kind: Entity
metadata:
  name: arisan-group
  module: arisan-master
  description: "Grup arisan — kumpulan anggota dengan iuran bulanan tetap"
spec:
  characteristic: master
  lifecycle: plain_crud
  display_field: name
  plural: arisan-groups
  fields:
    - name: code
      type: string
      required: true
      unique: true
      title: "Kode Grup"
    - name: name
      type: string
      required: true
      title: "Nama Grup"
    - name: monthly_amount
      type: money
      required: true
      title: "Iuran Bulanan"
  state_machine:
    field: status
    initial: active
    states:
      - { name: active, label: "Aktif" }
      - { name: completed, label: "Selesai" }
    transitions:
      # Approval inline: transisi ini ditahan sampai pasti.
      - from: active
        to: completed
        via: complete
        approval:
          steps:
            - name: manager-check
              permission: manager-check
              approvers: 1
              escalation: { after: 4h, reassign: head-check }
          on_reject: { to: active }
  actions:
    - name: submit
      disabled: true
    - name: complete
      description: "Tandai grup selesai"
      required_permission: arisan-master.arisan-group.complete
      audit: true
  expose:
    - type: rest
      actions: [list, find, create, update, delete]

Atribut ​

<!-- generated:attributes -->

AtributTipeWajibContohDeskripsi
pluralstring—invoices
characteristicenum (master · transaction · reference · summary)✅masterCharacteristic is required: it is the axis the engine branches on
authEntityAuth—
persistPersistSpec—
fields[]Field—
actions[]Action—
input_sets[]InputSet—InputSets declares named, reusable lists of action inputs. A transition or
state_machineStateMachine—
events[]EventDecl—
deliver[]DeliveryDecl—
indexes[]IndexDecl—
row_scope[]FilterSpec—RowScope declares the row-level filters the server enforces on every read
create_scope[]CreateScopeSpec—CreateScope pins a dimension field on CREATE from a record the payload
scopeScopeDecl—Scope declares that this entity's rows are partitioned along a named
assignments[]AssignmentDecl—Assignments declares that this entity records which principal is assigned
maintained_bystring—MaintainedBy names the script that keeps a characteristic: summary
invariants[]InvariantDecl—Invariants declares properties that must hold for a `characteristic:
sources[]SummarySource—Summary-source contract for Entity characteristic: summary (Core Extended
join_keystring—
rebuildRebuildSpec—
extend_storageExtendStorage—
expose[]ExposeConfig—
backdate_policyBackdatePolicy—
forward_date_policyForwardDatePolicy—
hooks[]HookDecl—
rate_limitRateLimitSpec—1.4.1 resource-level rate limit (02-core-extended.md §17)
soft_deactivateSoftDeactivateDecl—1.4.10
cacheCacheSpec—Cache opts this entity into the framework read-through cache on
lifecycleenum (two_step_autosave · two_step_manual · plain_crud)—plain_crud
display_fieldstring—name

<!-- /generated:attributes -->

Referensi Struct ​

Nama struct di kolom Tipe di atas adalah tipe Go di pkg/spec/entity.go (dan pkg/spec/spec.go). Kontrak normatifnya didokumentasikan di docs/spec/backend/:

StructDokumentasi normatif
Field05-field-types.md — katalog tipe (§1), money (§2), validasi (§3), tree (§4), keamanan & computed (§5)
EntityAuth01-core-basic.md §1.4
Action01-core-basic.md §5
EventDecl01-core-basic.md §7
StateMachine02-core-extended.md §1
DeliveryDecl02-core-extended.md §3
BackdatePolicy / ForwardDatePolicy02-core-extended.md §9
HookDecl02-core-extended.md §15
RateLimitSpec02-core-extended.md §17
SoftDeactivateDecl02-core-extended.md §19
PersistSpec04-persist-backend.md
ExtendStorage03-entity-extension.md

Gotchas ​

  • Tidak ada spec.version. Kontrak versi ada di apiVersion (formspec.dev/v1); menulis version: di spec ditolak additional properties 'version' not allowed.
  • characteristic wajib — satu-satunya properti required di spec.
  • Reserved fields (owner, created_at, modified, doc_status, amends, amended_by, version) tidak boleh dipakai ulang sebagai nama field custom.
  • lifecycle adalah string enum — bukan map {doc_status: true}. Nilai yang valid ada di tabel Atribut di atas.
  • expose adalah array {type, actions} — shorthand all/read/none tidak ada. Omit expose = UI only (external API → 404).
  • target: di field relation diam-diam diabaikan → dangling relation. Pakai relation: { type: belongs_to, resource: <module.entity> }.
  • Update setelah submit selalu ditolak, tanpa pengecualian. Perubahan pasca-submit lewat custom action bernama.
  • transaction WAJIB punya field transaction_date eksplisit.
  • delete guard absolut (setara ON DELETE RESTRICT), tanpa override_permission.
  • Dua lapis state berjalan paralel: doc_status (framework) + custom state_machine (developer) — lihat docs/spec/backend/01-core-basic.md §1.6.
  • Approval bukan kind terpisah — dideklarasikan pada transisi (state_machine.transitions[].approval, backend/02-core-extended.md §2). Gate itu menahan transisi, jadi ia mengawal semua state asal transisi tersebut. Transisi tanpa via tidak bisa diberi approval (tidak ada namanya).
  • Duty approval = permission, bukan nama role (steps[].permission dan escalation.reassign), keduanya di-qualify jadi workflow.{module}.{entity}.{transition}.{duty} dan diberikan lewat grant { page: "workflow:{entity}.{transition}", actions: [{name: {duty}}] }.
  • escalation wajib lengkap: after + reassign, dan reassign tidak boleh menunjuk duty step itu sendiri (no-op) — formspec validate menolaknya.
  • Cross-ref: ai_skills/formspec-kinds · docs/spec/backend/01-core-basic.md · docs/spec/backend/02-core-extended.md

Standar terbuka (CC0) dengan implementasi referensi.