Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.encoreos.io/llms.txt

Use this file to discover all available pages before exploring further.

Spec ID: FA-18
Status: πŸ“‹ Contract frozen (implementation πŸ“ Planned β€” no production RPC until migrations ship)
Last Updated: 2026-04-26
Canonical integration reference for FA-18: revenue contracts, revenue schedules (invoice XOR contract source), deferred revenue, single fiscal period recognition runs, and GL posting via FA-02. Authoritative duplicates: Event payload is defined identically in EVENT_CONTRACTS.md Β§ FA-18. HTTP shape (if used) is defined in API_CONTRACTS.md Β§ FA-18. This file ties them together and documents GL line mapping and transport choice.

Integration Summary

FromToPatternDescription
FA-18FA-02RPC / eventBalanced JEs on recognition; fa_revenue_recognitions.journal_entry_id + journal_entry_line_id (revenue line for traceability)
FA-18FA-05FK / readfa_revenue_schedules.invoice_id β†’ fa_invoices
FA-18FA-13FK / readfa_revenue_contracts.project_id β†’ fa_projects
FA-18FA-01FKfa_revenue_recognitions.fiscal_period_id β†’ fa_fiscal_periods
FA-18PF-01Contextorganization_id on all tenant tables
FA-18FA-UX-15UX delegateSchedule creation wizard; same DDL and server validation (no parallel tables)

Transport (frozen)

PathWhen to use
Primary: public.fa_process_revenue_recognition(p_organization_id uuid, p_recognition_date date, p_fiscal_period_id uuid, p_user_id uuid)Server-side period run; SECURITY DEFINER; enforces RLS context; one fiscal period per call.
Optional HTTP: POST /api/v1/fa/revenue/recognizeThin wrapper (Edge Function or API route) that validates fa.revenue_recognitions.process, maps body β†’ RPC args, returns JSON matching HTTP response below.
Callers must hold PF-30 fa.revenue_recognitions.process (or equivalent) in addition to tenant RLS.

RPC: fa_process_revenue_recognition

Signature (frozen):
fa_process_revenue_recognition(
  p_organization_id uuid,
  p_recognition_date date,
  p_fiscal_period_id uuid,
  p_user_id uuid
) RETURNS TABLE(
  schedule_id uuid,
  recognition_amount numeric,
  journal_entry_id uuid
);
Semantics:
  1. Select active fa_revenue_schedules for p_organization_id that intersect the fiscal period identified by p_fiscal_period_id (via fa_fiscal_periods), have remaining_to_recognize > 0, and satisfy date window rules per spec.
  2. For each schedule, insert at most one fa_revenue_recognitions row for (revenue_schedule_id, fiscal_period_id) (UNIQUE).
  3. Update fa_revenue_schedules.total_recognized in the same transaction as the insert.
  4. Phase 1 GL scope (DEFERRED): Do not call fa_create_journal_entry() from fa_process_revenue_recognition() in Phase 1. Recognition rows are written with journal_entry_id IS NULL and journal_entry_line_id IS NULL. A Phase 2 task will post GL via FA-02 and back-fill the linkage. This boundary keeps Phase 1 self-contained and decoupled from FA-02’s not-yet-frozen RPC signature.
  5. Inserts MUST use ON CONFLICT (revenue_schedule_id, fiscal_period_id) DO NOTHING so the function is idempotent on retry.
Optional filter (HTTP only): If the HTTP layer accepts schedule_ids?: uuid[], it MUST filter to those IDs within p_organization_id only; omitting the array means β€œall due schedules” for the period (same as RPC-only callers invoking for the whole org period batch).

Event: revenue_recognized

Publisher: FA (FA-18)
Subscribers (planned): FA-02, FA-05, FA-13
Emit after a recognition row is committed (and ideally after GL post when GL is in scope for that run). Payload (frozen) β€” see EVENT_CONTRACTS.md:
{
  event_type: 'revenue_recognized';
  organization_id: uuid;
  recognition_id: uuid;
  revenue_schedule_id: uuid;
  fiscal_period_id: uuid;
  recognition_amount: number;
  recognition_date: date; // processing date
  recognition_period_start: date;
  recognition_period_end: date;
  journal_entry_id?: uuid;
  journal_entry_line_id?: uuid;
}

HTTP: Recognize revenue (optional wrapper)

Endpoint: POST /api/v1/fa/revenue/recognize
Logical mapping: Body β†’ fa_process_revenue_recognition with p_user_id = auth.uid().
Request:
{
  recognition_date: string; // ISO date
  fiscal_period_id: string;
  schedule_ids?: string[]; // optional filter; same-org only
}
Response (200):
{
  recognition_count: number;
  total_recognized: number;
  recognitions: Array<{
    recognition_id: string;
    revenue_schedule_id: string;
    recognition_amount: number;
    journal_entry_id?: string;
    journal_entry_line_id?: string;
  }>;
}
Errors: 400 invalid body / unknown period; 403 tenant or permission; 422 schedule not eligible (closed period, zero remaining, etc.). Do not echo internal SQL.

GL mapping (FA-02)

Schedule sourceDebit (examples)Credit
Invoice-linked (invoice_id set)Accounts receivable (or org default per FA-01)Revenue
Linked to deferred revenue workflowDeferred revenue liabilityRevenue
Exact account resolution: FA-01 CoA + org policy; implementation calls FA-02’s standard journal entry API/RPC. journal_entry_line_id SHOULD reference the credit revenue line (or documented pair) for audit trail per FA-18 spec clarifications.

Planned consumers (Phase 2)

  • invoice_sent (FA-05), contract_signed (FA-13) β€” auto-create schedules/contracts; not in Phase 1.

Spec reference

PENDING_CONTRACTS: FA-18 integration IOU resolved 2026-04-26 β€” row archived under Resolved Stubs.