Skip to content

Quick start — financial statement to ACRA-filed XBRL

A narrative walkthrough of the XBRL filing flow from the staff side. By the end you'll have moved one client through one full filing — source document ingested, every line item tag-mapped to an ACRA element and human-confirmed, the 144-rule validation run, BizFinx workbook exported, optional client sign-off captured, ACRA filing reference recorded. Every section links into the matching how-to runbook for click-by-click detail and into the troubleshooting page that covers the most common stumble at that step.

The story below follows one client end to end. We'll use Meridian Engineering Pte Ltd — a hypothetical non-listed Singapore company with a December year-end, filing under FULL_XBRL against ACRA Taxonomy 2026 v1.0, accounting standard SFRS. Anchor the steps on whichever client you're actually running; the surfaces are identical.

IMPORTANT

The export gate has no override path. Two of the five non-negotiable rules from cursorrulesno XBRL output without passing validation and every tag mapping must be human-confirmed — are enforced by assertExportAllowed() and live in packages/xbrl/src/export-gate.ts. If you find yourself wanting to "just get the export out", the right answer is fix the mapping or fix the rule failure. There is no escape hatch.

NOTE

If you're new to the dashboard, start with the dashboard tour first. If you're new to the codebase, walk the manual testing playbook — it exercises every layer (schema, constitution, gate, FSM) in the current Phase 0 / Phase 2-foundation state.

Cast of characters

RolePlays
Platform AdminSets up the client record once — xbrlConfig, entity type, default entry point, taxonomy version, accounting standard, UEN
XBRL PreparerCreates the filing, ingests the source document, walks every line item, confirms or overrides tag mappings
XBRL ReviewerRuns validation; exports BizFinx XLSX + XBRL XML; marks filed against ACRA; appends synonyms to the mapping library when warranted
Senior AccountantSenior judgment on persistent validation failures; cross-product hand-off when the source is an FS engagement
Client approverOptional pre-submission sign-off via portal — confirms UEN and the period being filed

0. Confirm the client is configured

An XBRL filing client needs:

  • Enabled products including XBRL Filing
  • An xbrlConfig with entityType (e.g. NON_LISTED_COMPANY_FULL), defaultEntryPoint (e.g. FULL_XBRL), taxonomyVersion (e.g. acra_2026_v1), accountingStandard (SFRS / SFRS_SE / IFRS), and the entity's uen
  • One approver contact for the optional portal sign-off

Open Clients in the staff dashboard sidebar, click into Meridian. The setup health panel goes green when the essentials are in place.

Onboard an XBRL clientConfigure xbrlConfig for a client

1. Create the filing

Open Meridian; click New XBRL filing. Fill in:

  • Period start2024-01-01
  • Period end2024-12-31
  • Entry point — defaults from xbrlConfig.defaultEntryPoint; override per filing (e.g. an FSH variant)
  • Entity type — defaults from xbrlConfig.entityType
  • Accounting standard — defaults from xbrlConfig.accountingStandard
  • Taxonomy version — defaults from xbrlConfig.taxonomyVersion. This is pinned at create time and immutable thereafter. A future ACRA taxonomy release lands as a side-by-side constitution file; in-flight filings continue against their pinned version.
  • (Optional) FS engagement — when set, the cross-product Phase 3 hand-off is available at step 2.

Submit. Filing created at DRAFT. URL settles to /dashboard/xbrl/<filingId>.

Create an XBRL filing

2. Ingest the source document

Two paths. Pick one.

Path A — DOCX or PDF upload (independent path)

Open the Documents tab on the filing. Click Upload source document and drop in Meridian's financial-statements DOCX or PDF.

The handlers run in sequence:

  1. ingest-fs-document — persists the bytes via the File model with key prefix xbrl/<clientId>/<filingId>/source.{docx,pdf}; computes SHA-256; inserts XbrlSourceDocument.
  2. extract-line-items — reads the file; parses tables (DOCX via mammoth; PDF via pdf-parse + table heuristics); normalises amounts (strip commas, parentheses → negative); inserts XbrlLineItem rows with (statement, label, valueCurrent, valuePrior, sourcePage, sourceLine). Filing transitions DRAFT → DOCUMENTS_INGESTED.
  3. suggest-tag-mappings — for each line item: exact-match against mapping_library.json synonyms (case-insensitive); on miss, fuzzy-match against taxonomy element labels filtered by entry point and statement section; persists XbrlTagMapping rows with confirmedById = NULL and alternatives populated. Filing transitions DOCUMENTS_INGESTED → MAPPING_IN_PROGRESS.

For Meridian a typical run on a 14-page statement DOCX yields ~85 line items across balance_sheet, income_statement, cash_flow, equity_changes, and notes statements.

Path B — From an FS engagement (cross-product, Phase 3)

If Meridian's FY2024 financial statements were already built in the platform's Financial Statements module, click Pull from FS engagement on the Documents tab. The handler reads the latest FsGeneratedStatement.statementsJson and expands it directly into XbrlLineItem rows — skipping the DOCX parse entirely. Where the SFRS taxonomy key has a known ACRA element correspondence in mapping_library.json with HIGH confidence, the mapping is auto-confirmed; MEDIUM / LOW rows land unconfirmed for manual review.

NOTE

Path B requires the FS engagement to be at NOTES_COMPLETE and the client must have the FS module enabled. The two products share the same clientId.

Upload a source documentPull from an FS engagementSource PDF yielded zero line items — usually a rasterised PDF → DOCX has tables but they didn't parse — table layout edge case in mammoth

3. Confirm tag mappings

Open the Mappings tab. Master-detail layout: line-items list on the left (filterable by statement and by confirmation status), element-confirmation panel on the right.

For Meridian's 85 line items, the suggestion engine produced:

  • 54 with HIGH confidence (exact-match against the synonym library)
  • 22 with MEDIUM (fuzzy-match, top suggestion confident)
  • 6 with LOW (fuzzy-match, multiple plausible candidates in alternatives[])
  • 3 with no suggestion (label too generic; manual search required)

Walk every row. Three actions per line item:

  • Confirm — accepts the top suggestion. Sets confirmedById and confirmedAt.
  • Pick alternative — opens the alternatives[] list (top-N candidates from the suggestion engine). Choose; confirm.
  • Search and pick — opens the taxonomy search box, filtered by the filing's entry point and the line item's statement section. Pick; confirm.

For one row — "Software development costs capitalised" — there's no good match. Click Search, type software, find sg-as_IntangibleAssetsRelatedToComputerSoftware, confirm. The label is canonical enough to be worth saving: click Save as synonym. The handler writes {label: "Software development costs capitalised", target_element_id: "sg-as_IntangibleAssetsRelatedToComputerSoftware", confidence: "high"} into mapping_library.json and emits an AuditEvent xbrl.mapping.synonym_added. Future filings for any client will pick this up.

IMPORTANT

Save-as-synonym affects every future filing across every client. ADD_MAPPING_SYNONYM is restricted to XBRL_REVIEWER, SENIOR_ACCOUNTANT, PLATFORM_ADMIN for exactly that reason. Use it for labels that are likely to recur across the firm's portfolio, not for one-off client wording. The Phase 4 backlog includes per-client override files to limit cross-client blast radius — until then, the global library is shared.

When every line item has confirmedById != NULL, the filing is ready for validation.

Confirm tag mappingsOverride a tag mappingSave a new synonym to the mapping library — reviewer / senior-only → Suggestion confidence is all LOW — usually a label-normalisation surprise → Element search returns nothing for an obvious concept — check the entry-point filter

4. Run validation

Open the Validation tab; click Run validation.

The handler enqueues run-xbrl-validation:

  • Loads every confirmed XbrlTagMapping
  • Loads the validation rules for the pinned taxonomyVersion via loadValidationRules(version)
  • Filters by entry point via rulesForEntryPoint(version, entryPoint) — for FULL_XBRL typically ~100 of the 144
  • Evaluates each rule's expression against the line-item values
  • Writes one XbrlValidationResult per rule with severity (ERROR / WARNING / INFO), passed (boolean), message, relatedElements

The UI splits into three panes:

PaneEffect on export
ErrorsBlocks export. The export gate raises VALIDATION_ERROR_PRESENT until every ERROR-severity row is passed = true or remediated
WarningsDoes NOT block export. Surfaces in the UI and on the filing log; ACRA can still reject the filing for warning-only issues, so don't ignore
InfoInformational only. Pass / fail recorded for completeness

For Meridian a typical first-pass run lands VALIDATION_FAILED with two errors and four warnings:

  • ERROR BR_totalling_001 — Total Equity + Total Liabilities does not equal Total Assets. Difference: SGD 12,400. Cause: a Deferred Tax Liability line item was mapped to sg-as_TradeAndOtherPayables instead of sg-as_DeferredTaxLiabilities.
  • ERROR BR_mandatory_011sg-dei_PrincipalActivities element is mandatory for non-listed companies but not present. Cause: the source DOCX had Principal Activities in the Directors Report only; the line-item extractor didn't surface a fact. Fix: search the taxonomy, find the element, and the mapping panel offers to create a synthetic line item.
  • WARNING BR_arithmetical_005 — Profit Before Tax disclosed but no income-tax expense element provided. Cause: legitimate — Meridian had a tax loss carryforward and no current-year tax expense.
  • WARNING BR_cross_statement_003 — Retained-earnings closing in SOFP does not match SOCE closing. Difference: SGD 200 (rounding). Acceptable on inspection.

Fix the errors: revisit the mappings; revise. Re-run validation. The handler upserts the same (filingId, ruleId) rows; the prior failures are overwritten.

Now the filing transitions VALIDATION_FAILED → MAPPING_IN_PROGRESS → VALIDATION_PASSED.

Run validationResolve a validation errorSame error keeps coming back after 3 iterations — escalate to Senior Accountant; the rule expression may need scrutiny → Warning I disagree with — document the rationale on the filing log; warnings do not block

5. Export — BizFinx XLSX and XBRL XML

XBRL_REVIEWER, PLATFORM_ADMIN (and Senior Accountant for everything short of MARK_XBRL_FILED) can export.

Open the Exports tab. Two buttons:

  • Generate BizFinx — produces a multi-sheet Excel workbook (Income Statement / Balance Sheet / Cash Flow / Equity Changes / Filing Information) shaped for upload to ACRA's BizFinx Preparation Tool.
  • Generate XBRL XML — produces an XBRL instance document with contexts (instant for balance-sheet, <startDate>/<endDate> for flow), units (iso4217:SGD), and one fact per confirmed mapping.

Click one. The handler enqueues generate-bizfinx-xlsx or generate-xbrl-xml. Before any byte is written, assertExportAllowed() runs:

Reason raisedConditionWhat to fix
NO_LINE_ITEMSFiling has no XbrlLineItem rowsRe-upload the source document
NO_VALIDATION_RUNNo XbrlValidationResult rows existRun validation
VALIDATION_ERROR_PRESENTAt least one row with severity = ERROR AND passed = falseFix the underlying mapping / data; re-run validation
UNCONFIRMED_TAG_MAPPINGAt least one XbrlTagMapping.confirmedById IS NULLOpen the mappings tab; filter for unconfirmed; confirm each one

The HTTP layer translates XbrlExportBlockedError to HTTP 422 with the typed reason. The UI shows the offending line items / rule ids inline.

On pass:

  • The artifact is built
  • Persisted via File model with key prefix xbrl/<clientId>/<filingId>/<artifact>-v<n>.{xlsx,xml}
  • An XbrlOutputArtifact row is inserted with kind, versionNo, signed URL
  • Filing transitions VALIDATION_PASSED → EXPORTED (first time only; subsequent exports add new artifact versions but keep the status)

Both export paths run the gate. Defence in depth: the service-layer and the worker both check, so a future code change can't bypass.

Generate BizFinx XLSXGenerate XBRL XMLExport refused with UNCONFIRMED_TAG_MAPPING — filter mappings for unconfirmed; the UI will tell you exactly which rows → Export refused with VALIDATION_ERROR_PRESENT — open the Validation tab; address each error

6. (Optional) Client portal sign-off

If Meridian wants to sign off before submission to ACRA, click Send to client for sign-off on the filing. The handler creates a PortalInvitation with resourceType = XBRL_FILING, 30-day expiry; the approver gets an email:

  • Subject: XBRL filing ready for sign-off: Meridian Engineering Pte Ltd (2024-01-01 → 2024-12-31)
  • Body: Filing period, UEN, entry point, validation-passed badge, and a single Open the sign-off portal button.

The portal shows:

  • Filing summary (UEN, period, entry point, taxonomy version)
  • Statement-level previews (Balance Sheet totals, P&L totals)
  • A UEN confirmation input — the approver must echo Meridian's UEN to confirm they're signing the right entity
  • Two CTAs: Approve and Request revision
If they pick…EffectYour next step
ApproveDecision captured with timestamp; staff notifiedSubmit to ACRA; click Mark filed
Request revisionComment captured; staff notified; filing back-routes to MAPPING_IN_PROGRESSAddress the comment; re-run validation; re-export; re-send portal link

Dispatch the XBRL portal linkHandle a client revision request

7. Submit to ACRA and Mark Filed

This step is out-of-band — the platform does not submit to ACRA automatically.

  1. Open the Exports tab; download the BizFinx XLSX (latest version).
  2. Open ACRA's BizFinx Preparation Tool. Upload the workbook. Resolve any tool-side prompts.
  3. Submit through BizFinx. Capture the ACRA filing reference from the acknowledgement.
  4. Back in the platform, open the filing detail; click Mark filed. Provide the ACRA filing reference. Filing transitions EXPORTED → FILED. filedAt and filedById are recorded.

IMPORTANT

Only XBRL_REVIEWER and PLATFORM_ADMIN can Mark filed. The boundary deliberately matches human accountability with the regulator — whoever marks the filing is the one taking responsibility with ACRA. Even Senior Accountants who can do everything else short of filing cannot do this.

Mark a filing as filed with ACRAACRA rejected the filing after submission — back-route to MAPPING_IN_PROGRESS; fix; re-export; re-submit

8. Archive

When the audit cycle closes, click Archive. The filing transitions FILED → ARCHIVED and becomes read-only. The retention policy (default 7 years from period end; configurable per jurisdiction) applies.

What you've just done

You've shipped Meridian through one complete XBRL filing: source document ingested, every line item tag-mapped to an ACRA element and human-confirmed, the 144-rule validation passed, BizFinx workbook and XBRL XML produced through the gate, optional client sign-off captured, ACRA filing reference recorded, filing archived. The five non-negotiable rules — Rule 1 (no taxonomy literals), Rule 2 (no output without passing validation), Rule 3 (every mapping human-confirmed), Rule 4 (taxonomy version is first-class), Rule 5 (regression suite green) — were all enforced in code, in tests, and in your work.

Where to go next

Cheat sheet — what to do when X

If…Open…Do…
Source PDF yielded zero line itemsFiling → DocumentsAsk the client for a DOCX or a text-extractable PDF; or use the cross-product from-fs-engagement path
Suggestion confidence is all LOWFiling → MappingsCheck the entry-point filter on element search; verify the source statement headings — see All low confidence
Export refused: UNCONFIRMED_TAG_MAPPINGFiling → MappingsFilter for unconfirmed rows; confirm each — see Export blocked: unconfirmed
Export refused: VALIDATION_ERROR_PRESENTFiling → ValidationOpen each error row; trace relatedElements; fix at source — see Export blocked: validation
Save-as-synonym is disabledFiling → MappingsYou don't hold ADD_MAPPING_SYNONYM — escalate to Reviewer or Senior Accountant
Mark Filed button is disabledFiling detailOnly XBRL_REVIEWER or PLATFORM_ADMIN may mark filed
Validation rule keeps failing across iterationsFiling → ValidationEscalate to Senior Accountant; the rule expression may need scrutiny — see Validation loops
Need to file the same period for a different entity typeDon't reuse the filingCreate a new filing with the correct entity type; the taxonomy version is per filing
ACRA rejected after Mark filedFiling detailBack-route to MAPPING_IN_PROGRESS (EXPORTED → MAPPING_IN_PROGRESS is allowed); fix; re-export — see ACRA rejection
You took a wrong actionActivity logEvery state change is logged with the actor — see Recover from a mistake

Internal use only — BreezyCorp