Skip to content

Periods & the close

The month-end close is the central workflow of accounting software. It is also the workflow that generic dashboard components cannot express at all, because it depends on a concept they don't have: a period has a state, and that state governs what the UI may offer.


1. Fiscal calendars

type FiscalCalendar = {
  /** 1–12. A June year-end means fiscalYearStartMonth = 7. */
  fiscalYearStartMonth: number;
  /** How periods are cut. */
  type: "calendar" | "4-4-5" | "4-5-4" | "5-4-4" | "13-period";
  /** Which calendar year labels the FY. A FY starting Jul 2026 may be "FY26" or "FY27". */
  yearLabelConvention: "start" | "end";
  /** Some entities run a 53-week year periodically. */
  weekAlignedYearEnd?: boolean;
};

Never assume January. This is the most common fiscal bug in finance UI, and it is silent — a Q1 label that means Jan–Mar for an entity whose Q1 is Jul–Sep produces confident, wrong analysis.

Retail calendars (4-4-5 and friends) are not exotic. They make every "month" a whole number of weeks so week-over-week comparison works. Consequences:

  • A "month" is 28 or 35 days, not a calendar month.
  • Period boundaries fall mid-calendar-month.
  • Every 5–6 years there is a 53rd week, and the extra week distorts every year-over-year comparison in that year. Flag it — a component that shows +8.4% YoY in a 53-week year without a note is misleading.

UI rules:

  • PeriodPicker renders the fiscal label and the resolved dates, always: FY26 Q1 (1 Jul – 30 Sep 2026).
  • Never render a bare Q1, Sep, or Last quarter.
  • Comparative columns state their own resolved period; the header never says "Prior".

2. Period states

A period is not just a date range. It is a state machine, and the state determines the available actions.

┌──────────┐   ┌─────────────┐   ┌────────────┐   ┌────────┐   ┌───────┐
│  future  │ → │    open     │ → │ soft close │ → │ closed │ → │ filed │
└──────────┘   └─────────────┘   └────────────┘   └────────┘   └───────┘
                      ↑                                │
                      └────── reopen (approval) ───────┘
State Posting Who can post UI treatment
future Blocked — Greyed in every picker; selecting it explains why
open Free Anyone with the role Normal
soft close Adjusting entries only Controller and above Amber banner; the entry form defaults to adjusting
closed Blocked Nobody without a reopen Lock glyph; statements marked final
filed Blocked Nobody. Never reopened; corrections go through restatement, revision or a current-period adjustment. Lock + "Filed" badge; restatement workflow only

The PeriodStatus banner

Every surface scoped to a period displays its state. This is not decoration — it is the answer to "why can't I post this?", asked before the user has to ask.

🔒  September 2026 · Closed 4 Oct 2026 by A. Rivera
    Entries dated in this period must be posted to October and will
    be flagged for cutoff review.                        [Request reopen]

Three things in that banner: the state, the provenance (who and when), and the next action. A lock icon alone is a dead end.

Reopening

  • Requires an approval from a role that did not request it.
  • Writes to the audit trail with a mandatory reason.
  • Invalidates every statement generated from that period. Any export or saved report carrying that period is marked stale, because a PDF someone emailed to a lender is now wrong.
  • The UI states the blast radius before confirming: "Reopening September will mark 4 published statements as superseded."

3. Cutoff

Cutoff is the boundary problem: a transaction dated in one period, entered in another. Getting cutoff wrong shifts revenue or expense between periods, which is the most common form of unintentional misstatement.

The CutoffWarning component fires when:

  • An entry's transaction date falls in a closed or soft-closed period.
  • An entry's date is within N days of a period boundary (configurable, default 5) and the period is in close.
  • A bank transaction settles in one period but was initiated in another.
  • An invoice dated in the prior period arrives after close.

The warning is inline at the date field, not a toast, and it states the consequence:

This is dated 29 Sep, which is in a closed period. It will post to October. If it belongs in September, request a reopen, or record it in October as an out-of-period adjustment.

That last clause is the useful part: it names the two legitimate remedies rather than just blocking.


4. The close pipeline

Lopifi models the close as a sequence of gated sections. This structure comes from how closes are actually run, and it drives CloseChecklist, CloseStatus, and the dashboard.

# Section Gate — what "done" means
1 Cutoff & capture All source documents in; AP and AR cutoff tested
2 Cash Every bank and card account reconciled; exceptions explained
3 Subledgers AR and AP agree to the GL control accounts
4 Schedules Prepaids, accruals, deferred revenue, fixed assets rolled forward and tied
5 Adjusting entries Accruals, depreciation, amortization, provisions, reclasses posted
6 Balance sheet tie-out Every BS account supported by a schedule or reconciliation
7 Review & flux Material variances explained; statements reviewed and signed off

Rules:

  • Sections gate in order. You cannot tie out the balance sheet before the schedules are rolled. The UI shows downstream sections as blocked, with the blocker named.
  • Every check has an owner, a due date, and a state: not started → in progress → blocked → done → reviewed.
  • A blocked item names its blocker and who owns it. "Blocked: waiting on Sep bank statement — Treasury."
  • Sign-off is irreversible and audited. It uses HoldToConfirm and writes who, when, and on what version of the numbers.
  • The close percentage is by weighted check, not by count. Ten trivial checks and one bank rec is not 91% done.

5. Reconciliation vs tie-out

Two different controls, constantly conflated, and each has its own component.

Bank reconciliation Balance sheet tie-out
Question Does our cash record match the bank's? Is this balance supported by evidence?
Compares Book cash vs. bank statement GL balance vs. a supporting schedule
Output Reconciling items (timing differences) A walk-down with a difference of zero or an explanation
Component ReconciliationView AccountTieOut
Applies to Cash and card accounts Every balance sheet account

The bank reconciliation summary

The standard form, and the component renders exactly this:

  Bank statement balance                    412,880.14
  Add: deposits in transit                    8,420.00
  Less: outstanding checks                  (22,140.55)
  Add/less: other reconciling items               0.00
                                           ────────────
  Adjusted bank balance                     399,159.59
  Book (GL) balance                         399,159.59
                                           ════════════
  Difference                                      0.00   ✓

The difference line is the whole component. It is always visible, never scrolls away, and it is the number the user is working to zero. When it is non-zero, that is the primary state of the screen.

The tie-out walk-down

  1310 · Prepaid expenses
  GL balance at 30 Sep 2026                  84,220.00
  Supporting schedule closing balance         84,220.00
                                           ────────────
  Difference                                       0.00   ✓  Tied
  Supported by: Prepaid schedule (14 items) · reviewed A. Rivera 3 Oct

Every balance sheet account gets one. An account with no supporting evidence is itself a finding — AccountTieOut renders an explicit "Unsupported" state rather than showing nothing.


6. Reconciling items and exceptions

A reconciling item is a legitimate timing difference. An exception is a break that needs work. The UI must not conflate them.

Kind Meaning Aging behavior
Deposit in transit Booked, not yet on the bank statement Should clear next period; flag if > 5 days
Outstanding check Issued, not yet cashed Flag if > 90 days; stale-dated after six months (a bank may refuse it, UCC §4-404). Still a liability — void and reissue, or escheat under state unclaimed-property law after the dormancy period. Never write it back to income
Bank-only item Fee, interest, NSF the bank booked and we didn't Requires a journal entry. Should never age.
Book-only item We booked something the bank has no record of Investigate immediately
Unmatched No counterpart found The actual exception

Aging is the priority signal. A 3-day-old outstanding check is normal; a 200-day-old one is a control finding. ReconciliationView sorts exceptions by age descending by default, not by amount — old breaks are what auditors find.


7. Adjusting entries

The entries that make accrual accounting work. Each has a distinct shape, and AdjustingEntryForm offers them as templates rather than a blank journal entry.

Type Pattern Auto-reverses?
Accrual Dr Expense / Cr Accrued liability Yes — day 1 of next period
Deferral Dr Prepaid asset / Cr Expense No — released by schedule
Depreciation Dr Depreciation expense / Cr Accumulated depreciation No
Amortization Dr Amortization expense / Cr Accumulated amortization No
Revenue recognition Dr Deferred revenue / Cr Revenue No — released by schedule
Provision / allowance Dr Bad debt expense / Cr Allowance No — trued up each period
Reclassification Dr Account A / Cr Account B Sometimes
True-up Adjusts an estimate to actual No

The auto-reversal rule is critical. An accrual that doesn't reverse double-counts the expense when the actual invoice arrives and is coded to expense. AdjustingEntryForm defaults autoReverse to true for accruals and shows the reversal date inline: "Reverses 1 Oct 2026". Making the user remember this is how expenses get double-counted.

The reversal is created at posting time as a scheduled entry, visible in the next period before it posts — so a reviewer can see it coming.


8. Subsequent events

Events after the period end but before the statements are issued (or available to be issued, for an entity that is not an SEC filer). Two types, and the distinction has real consequences. ASC 855 calls them recognized and nonrecognized subsequent events; IAS 10 calls them adjusting and non-adjusting.

Type 1 — Adjusting Type 2 — Non-adjusting
Condition Existed at the balance sheet date Arose after
Example A customer whose finances were already deteriorating at 30 Sep files for bankruptcy in October; a lawsuit about a September incident settles A fire destroys a warehouse in October; the company issues debt or equity, or acquires a business
Treatment Adjust the statements (ASC 855-10-25-1) Disclose the nature and an estimate of the effect, if material (ASC 855-10-25-3, -50-2)

SubsequentEventLog captures these during the review window with the type, the date discovered, and the treatment decision. It matters because the same event handled the wrong way is a misstatement in one direction or an omitted disclosure in the other.


9. Restatement

When a closed and filed period is found to be materially wrong.

  • A restatement ("Big R", ASC 250-10-45-23) is required when the error is material to the previously issued statements: they are reissued, the cumulative effect lands in opening retained earnings of the earliest period presented, and the error is disclosed.
  • The prior period is not silently edited. A restatement entry is posted, and the comparative column is labeled "Restated" everywhere it appears.
  • The UI never shows a restated comparative without the label. A prior-year column that quietly changed between two reports destroys trust faster than the original error.
  • StatementTable supports a restated flag per period column, rendering the label in the header and a footnote naming the reason.
  • Errors immaterial to the prior period but material if corrected now revise the comparatives, labeled "As revised". Errors immaterial either way are corrected in the current period as an out-of-period adjustment. Materiality is assessed under both the rollover and iron-curtain approaches (SEC SAB No. 108), quantitatively and qualitatively (SAB No. 99). The materiality policy decides which, and the decision is recorded.

10. Period-scoped UI rules

Applying across every component:

  1. Every figure declares its period. No exceptions.
  2. Every period label shows resolved dates.
  3. Every period-scoped surface shows the period's state.
  4. A closed period's numbers cannot change, so any UI affordance implying they can is removed, not disabled.
  5. Comparatives are on the same basis, same framework, same entity set, and same currency. Mixing is blocked at the type level, not warned about at render time.
  6. A statement generated from a period that later reopens is marked superseded, wherever it was saved or exported.

Built against this document

The surfaces that implement what this argues — running, computing, or shaped by it.

Told when this spec changes

The docs are the contract the components are built against. When one changes, the component changes with it — and the copy in your repo does not. One email when that happens.

One address, no list rental, unsubscribe in one click.

Works in your QuickBooks Online or Xero file

Get your books closed every month

Lopifi is building AI bookkeeping that keeps your books closed on US GAAP as transactions happen, with a CPA review every quarter, for $200 a month. We’re not open yet.

$200/month when we open. No card now.