Offer letters
Valid sends the offer in three versions. Which one a candidate gets is chosen
per candidate, on the offer card, and recorded on the offer.
| Letter | When | Staging template id |
|---|---|---|
| Indonesian | The default, and the legally safest | 01a02f58-f962-774e-a1cc-935ae9332b35 |
| English | Candidates who do not read Indonesian | 01a02d60-0e52-7bd0-ae37-ec5f85e867e2 |
| Bilingual | Indonesian above English, Indonesian prevails | 01a02d8d-4fc9-7e7f-9b49-434f73d9610a |
All three are .dotx files in Obscura, in the category Offer Letter, and
all three declare the same 15 fields — so switching a draft between them never
invalidates values already typed.
Why Indonesian is the default
- UU 24/2009 Pasal 31 makes the Indonesian text the operative one for an
agreement with an Indonesian party. The English is a courtesy translation
either way. - UU 13/2003 Pasal 57: a PKWT not made in Indonesian is deemed PKWTT. An
English-only contract hire is accidentally permanent. - Two texts is two texts to maintain. A careful translation of the English
block still produced five substantive divergences, one of them a blocker
(gaji pokok bersih—gaji pokokis statutorily the gross basic wage).
Three reviewers caught it. Nobody runs three reviewers on the next edit.
None of this is a lawyer's opinion. The PKWT/PKWTT point in particular is worth
confirming with one.
How the portal finds them
OBSCURA_OFFER_TEMPLATE_CATEGORY (default Offer Letter). Obscura already
groups templates this way — Kop Surat for letterheads, Quotation for quotes
— and the category is editable from its admin, so a fourth offer letter becomes
available by being uploaded and categorised. No deploy.
The category is a gate, not a label: every template in Obscura shares one id
space, and a letterhead declares no fields, so filing an offer on one would
consume a permanent number for a document that is entirely {{TOKEN}}s.
| Setting | Default | What it does |
|---|---|---|
OBSCURA_OFFER_TEMPLATE_CATEGORY |
Offer Letter |
Which templates the picker offers |
OBSCURA_OFFER_TEMPLATE_ID |
first in category | The one a new draft starts on |
OBSCURA_OFFER_FOLDER_ID |
root | Where the document sits before publishing |
OBSCURA_OFFER_DOC_CLASSIFICATION |
confidential |
The document registry's code |
OBSCURA_OFFER_CLASSIFICATION |
rahasia |
The letter sifat — a different vocabulary |
OBSCURA_OFFER_READ_GROUPS |
— | Groups that may open a filed offer |
The last one is not optional in practice. A confidential letter's derived ACL is
its creator plus correspondence admins, and the creator is the portal's API key
— a bot. Without the grants, the people who made the offer cannot read it.
The form is not in this repository
GET /document-templates/{id}/fields is read at runtime, every time. Adding a
clause to the letter is a re-upload in Obscura; the field that fills it appears
in the console without a deploy. The completeness check is re-run against the
template's current declaration immediately before filing, so a .dotx
re-uploaded mid-draft cannot leave a blank in a numbered document.
The typographic punctuation trap
Obscura's docx→PDF step has no glyph for —, – or ’ and emits a literal
? for each.
It is not a warning, and it is invisible in the .docx — the XML holds the
right character the whole way through, so every check that reads the document's
text passes. Only the rendered PDF, which is what the candidate opens, is wrong.
VDI/OFR/260007 was filed that way, before this was found:
… in accordance with the Company ? s standard payroll schedule … (×3)
… (Karyawan tetap / Permanent, Hybrid ? Jakarta) … (×2)
… Efran Nathanael Direktur ? Val.id …
That letter is numbered and cannot be corrected. All three templates have been
re-uploaded with ASCII punctuation and re-verified: 0 ? in the rendered
PDF, no unfilled tokens, every value present.
The characters came in with Valid's own .dotx — Word inserts them by
autocorrect — so this is a trap for any future template, not just generated
ones. /tmp/sanitise_dotx.py in the session that found it does the replacement;
the check that matters is counting ? in the PDF, never in the .docx.
Proving a template without burning a number
Publishing consumes a number from a gapless sequence and cannot be undone.
official-copy does not. So:
POST /document-templates/{id}/use → a document, deletable
PUT /documents/{id}/fields → stamp NOMOR/TANGGAL by hand
POST /documents/{id}/official-copy → the merged PDF
GET /documents/{id}/versions/{v}/content → read it
DELETE /documents/{id} → gone
Use an unclassified document for this. A confidential one's bytes are
watermark-gated and the docx route answers protection.unmarkable_format;
classification has no bearing on how fields merge.
What the ceremony still is
Unchanged by the picker, and the reason the code is shaped the way it is:
pre-flight scheme, sifat, template — nothing exists, everything is cheap
/use a document exists → checkpoint: filed
read back values that did not land, caught free
publish-letter a NUMBER is consumed. Permanent. → checkpoint: numbered
set fields the number onto the page
official-copy the fields are finally merged → checkpoint: copied
acl the people who made the offer can read it
filed is a visible state in the console because it is the last honest cancel
point: the document exists, no number has been consumed, and both Obscura and
the portal will still take it back. After the number, neither will.