Welcome to FI.js Documentation

FI.js is a lightweight Local-First JavaScript framework designed to simplify the creation of data-driven single-page applications (SPAs). It empowers both programmers and non-programmers to build efficient, secure, and dynamic applications with ease. By engaging AI and focusing on transparency, extensibility, and connectedness, FI.js allows industries like banking, healthcare, insurance, and government (we call them Institutions .e.g. public and private) to transition from complex legacy systems to more agile development environments.

The problem we solve is that when an institutions' data is stored in the cloud, the institutions become “borrowers” of their own data. FI.js adopted a local-first approach to provide institutions to take back control of their data. In the context of serving heavily regulated industries, FI.js adapts a local-first approach to solve several critical problems related to data privacy, security, reliability, and operational efficiency. Here's a detailed breakdown:

  1. Data Privacy and Regulatory Compliance
    • Problem: Institutions operate in highly regulated environments where customer data must remain secure and often cannot leave the institution's private network. Sending sensitive data to the cloud can violate compliance regulations, such as GLBA (for banking), HIPAA (for healthcare), or state-level financial data protection laws.
    • FI.js Local-First Solution:
      • Data is processed and stored on local devices within the institution’s secure infrastructure, ensuring compliance with strict regulations.
      • Minimizes exposure to third-party cloud providers, reducing the risk of data breaches and unauthorized access.
  2. Data Security and Risk Mitigation
    • Problem: Institutions face significant risks from cyberattacks, ransomware, and unauthorized access when relying on centralized cloud-based systems.
    • FI.js Local-First Solution:
      • Storing and processing data locally reduces attack surfaces by eliminating the need for continuous cloud interaction.
      • Local-first systems manage state locally, decentralizing the data and reducing the incentive for large-scale breaches.
      • Protects against accidental leaks or vulnerabilities introduced by third-party integrations.
      • Sensitive financial data is kept within the institutions' internal network or on secure devices, limiting exposure.
  3. Disaster Recovery and Business Continuity
    • Problem: Relying on centralized systems can make institutions vulnerable to catastrophic failures or data loss during outages or cyberattacks.
    • FI.js Local-First Solution:
      • Local-first architecture ensures critical operations continue to function locally even if legacy systems and the Internet are unavailable.
      • Institutions have control over their data under the local-first architecture--knowing where FI.js data sources are located, how data is accessed, and how data is preserved.
  4. Extensibility and Transparency
    • Problem: software systems issues arises from the tension between growing complexity, user control, and both the need predictable results and the ability to create solutions to business problems without or limited use of developers.
    • FI.js Local-First Solution:
      • FI.js uses accessible and open data formats (e.g., JSON, JavaScript) stored locally, making it easier for developers and non developers to build new apps, libraries, and features.
      • FI.js rejects black-box behaviors, giving users full insight into operations and data flow.

Quick Start

This Quick Start guide will walk you through setting up FI.js and building & running a simple application. FI.js includes single page applications that work right out of the box--no learning curve to begin using FI.js. You'll learn how to:

  1. Download and set up the FI.js framework.
  2. Run the application using test data.
  3. Understand how the framework works at a high level through this example.
  4. Review a basic FI.js application using a sample appConfig.

Step 1: Download the FI.js Framework

  1. Visit the FI.js GitHub Repository
  2. Download the Repository
    1. Click the green "Code" button located near the top right corner.
    2. Select "Download ZIP" from the dropdown menu.
    3. Save the ZIP file to a directory of your choice on your computer.

Step 2: Extract and Set Up the Framework

  1. Extract the ZIP File
    1. Navigate to the directory where you saved the ZIP file.
    2. Right-click the ZIP file and select "Extract All..." or use your preferred extraction tool.
    3. Choose a destination folder for the extracted files.

Step 3: Prepare the Sample Data

Step 4: Open the Application in a Browser

  1. Open the Quickstart Application
    1. Double-click Quickstart.html to open it in your default web browser.
    2. Find and open the Quickstart.html file.
    3. Alternatively, right-click the file, select "Open with", and choose your preferred browser.

Step 5: Interact with the Application

Result
200106555 (2)2392$1,212,609.43
200102722 (1)2392$313,590.84

Step 6: Review the App Configuration

  1. In Quickstart.html, locate the <script> section where appConfig is defined. Here's the code for reference:
  2. const appConfig = { description: 'App compiles the average lifetime principal balances of loans opened within a select period of time', libraries: [ 'financial' ], formula: 'loan.open > "2020-10-31" && loan.open < "2024-11-03" ? loan.averageBalance : null', groupBy: 'portfolio', presentation: { columns: [ { heading: 'Branch', field: 'branch' }, { heading: 'Officer', field: 'owner' } ], } };
  3. Explanation of the No-code configuration:
    • description (optional): App Authors can describe their app to make it easier to understand and share.
    • libraries: Specifies the APIs and libraries the app uses. Libraries are collections of central dependencies: functions, attributes, and dictionaries--which are assembled for specific functionalities and help maintain code organization and reusability. In this example, the averageBalance function in the financial library is used to calculate the average principal balance. Note: Functions, attributes, and dictionaries are defined later in this guide.
      • Purpose: Group related components for modular application development.
      • Definition: Created for particular sets of functionality, such as financial calculations or organizational data.
    • formula: Act as the kernel of the FI.js framework, coordinating the interaction between raw data, libriaries, advanced operations, and outputs. This formula checks if each loan in data source is opened between October 31, 2020, and November 3, 2024. If true, it returns the average loan principal; otherwise, the loan is ignored from the final results.
    • groupBy: Formula results are grouped and aggregated by field specified by groupBy. In this example, results are grouped by the portfolio field. For example, results of all instances of a particular portfolio will be combined.
    • presentation: Defines the presentation layer of FI.js apps. If you define columns, FI.js will create a table to display formula results. If you define form fields (e.g. input) FI.js will render the results in a form. Quickstart configures two columns to display app results, showing Branch and Loan Officer.

Core Concepts

FI.js emphasizes clarity, transparency, and iterative development. It streamlines the creation of Single-Page Applications (SPAs) and encourages the fusion of human reasoning with AI-driven insights, leading to faster, more informed decision-making. Understanding the core components of FI.js is essential for building robust and efficient applications. These components work together to handle data processing, logic execution, and presentation within your single-page applications (SPAs).

  1. Formulas
  2. Formulas are the heart of FI.js, defining and evaluating the logic of applications and data transformations using a human-readable syntax.

    • Purpose: Perform dynamic calculations and data filtering.
    • Syntax: FI.js formulas use a combination of arithmetic operations, conditional operators, and truth propagation.

    Understanding Variables in Formulas

    • Variables in FI.js formulas represent data fields or properties derived from your data sources. They allow formulas to perform operations based on the values of these fields. Here's a breakdown of how to define and use these variables:
    • 1. Data Sources and Fields

      Variables such as loan.open are structured as source.field, where:

      • source (object identifier): The name of the data source (e.g., loan).
      • field (property): The specific data attribute within the source (e.g., open).

    To define these variables, ensure that your data sources are correctly configured in your single page application and that each source contains the necessary fields.

    Example Formula:

    loan.open > "2020-10-31" && loan.open < "2024-11-03" ? loan.principal : null

    This formula checks if the loan's open date is between October 31, 2020, and November 3, 2024. If true, it returns the loan principal; otherwise, it returns null.

  3. Functions
  4. Functions in Fi.js are reusable JavaScript functions used for calculations or data manipulation within your application.

    • Purpose: Encapsulate complex logic and operations.
    • Definition: Defined within libraries to ensure consistency and reusability.

    Example Function:

    const functions = {   loanPayment: {     description: "Calculates the monthly loan payment based on principal, annual rate, and amortization months",     implementation: function(principal, annualRate, amortizationMonths) {       const monthlyRate = annualRate / 12;       const payment = principal * (monthlyRate / (1 - Math.pow(1 + monthlyRate, -amortizationMonths)));4       return payment.toFixed(2);     }   } };

    This function calculates the monthly loan payment based on the principal amount, annual interest rate, and the number of amortization months.

  5. Attributes
  6. Attributes are constants or fixed values used throughout the application. They provide essential data points that can be referenced in formulas and functions.

    • Purpose: Store static values or configurations.
    • Definition: Defined within libraries for organized access.

    Example Attribute:

    const attributes = {   loanServicingFactor: {     description: "Factor used to calculate loan servicing costs",     value: 0.0025,   }
    };

    This attribute defines a servicing factor used in calculating loan servicing expenses.

  7. Dictionaries
  8. Dictionaries are key-value pairs used for data lookups and mappings. They allow for flexible data retrieval and manipulation based on predefined keys.

    • Purpose: Handle predefined sets of values, such as interest rates or loan classifications.
    • Definition: Organized within libraries for consistent access across the application.

    Example Dictionary:

    annualOperatingExpense: { checking: { description: "The checking account annual operating costs", values: { "Consumer": 112, "Business": 145 } }, savings: { description: "The savings account annual operating costs", values: { "Consumer": 28, "Business": 56 } } }

    This dictionary maps various loan types to their respective identifiers, facilitating easy lookups within formulas and functions.

  9. Libraries
  10. Libraries are collections of functions, attributes, and dictionaries organized for specific functionalities. They enable modular development, maintain code organization, and enhance reusability. Expreienced developers can create their own libraries following the libary schema.

    • Purpose: Group related components for modular application development.
    • Definition: Created for particular sets of functionality, such as financial calculations or organizational data.
    • Example Library Structure:

      const libraries = {   financial: {     functions: { /* Financial functions here */ },     attributes: { /* Financial attributes here */ },     dictionaries: { /* Financial dictionaries here */ },   },   organization: {     functions: { /* Organization functions here */ },     attributes: { /* Organization attributes here */ },     dictionaries: { /* Organization dictionaries here */ },   } };

    • Process: loading libraries in apps (SPAs) features:
      1. Support for Local and Remote Libraries:
        • Local libraries are JavaScript files stored within the project directory.
        • Remote libraries are APIs fetched over HTTP/HTTPS
      2. Offline-First Design:
        • Remote API responses are cached in IndexedDB. This is an intentionally simple and easy to understand approach.
        • If offline, the application retrieves data from the IndexedDB cache.
        • If data exists in the cache and is less than 24 hours old, it is used instead of making a network request.

Data Flow

Data in FI.js is handled through a unidirectional data flow, ensuring consistency, predictability, and easy debugging. State management is centralized, making it simple to understand and manipulate.

Data Handling

FI.js data handling approach is simple yet robust. You can connect to various data sources—APIs, databases, or in-memory structures—and transform them into meaningful, reactive components.

Statistics

The following statistics are available to Fi.js libraries

AI Integration

FI.js integrates seamlessly with AI models, helping to auto-generate UI elements, recommend code patterns, or assist with complex logic. This synergy between human and AI input opens new frontiers in rapid development and innovation.

Security & Transparency

FI.js is Local-first, a design and architectural principle in software development that prioritizes running applications and storing & connecting data sources locally on a user's device rather than relying solely on cloud-based services. Local-first and FI.js is about ownership and empowerment; we focus on providing offline-first functionality, tranparency, control, better privacy, and faster performance by emphasizing the local environment. Here's a detailed breakdown:

  1. Offline-First Functionality:
    • Applications should work seamlessly without an internet connection. Data is stored and processed locally, and unlike typical Local-first designs, FI.js does not synchronize with remote services.
    • Benefit: Offline functionality ensures uninterrupted usage.
  2. Data Privacy and Ownership:
    • Data resides on the user's device and inside the organization's security edge, giving them more control and eliminating the reliance on external servers. This ensures better privacy and security.
    • Users have complete control as they know exactly where their data is stored—on their local device—giving them full ownership.
    • No Hidden Transfers are permitted, since data is processed locally, there are no opaque processes transferring or storing it on remote servers without user knowledge.
    • Benefit: Sensitive data stays local and is less vulnerable to breaches, and no more worries about your vendor staying in business to support your platform.
  3. Portability and Transparency:
    • Users can use the application independently of any central service, which reduces vendor lock-in.
    • Local-first design inherently improves transparency, offering users clear insight and control over how their data is used and stored.
    • Benefit: Reduces reliance on expensive cloud infrastructure and enforces 100% transparency.
  4. State Management:
    • The current state is limited to the local machine, local Javascript runtime code, loaded DOM, defined data sources, and preloaded APIs. Nothing is distributed to the 'cloud' e.g. eliminates the dance between front-end and back-end code. And no seven figure AWS bills.
    • FI.js defines inputs and outputs, so the current state is well-managed, each change is predictable, enabling AI to operate on reliable data.
    • Benefit: Maintaining a clear and authoritative snapshot of all relevant data and functions—offers significant advantages, particularly when integrating AI.

Formulas

Formulas

In the FI.js framework, formulas serve as the core mechanism that connects data with functions, enabling powerful interactions. They allow users to perform dynamic calculations across multiple data sources, execute complex financial and analytical operations, and deliver results to defined outputs—all within a consistent, no-code, no-SQL, and human-readable syntax. Before diving deeper, let’s explore the syntax that makes it all possible.

In FI.js, formulas act as the kernel of the framework, coordinating the interaction between raw data, advanced operations, and outputs. As the foundation of the system, formulas provide:

  1. Central Coordination: Directing how data flows and is processed from sources to outputs.
  2. Simplified Abstraction: Translating simple syntax into complex computations.
  3. Dynamic Adaptability: Adjusting to various operations, from simple functions to AI-powered insights.
  4. Empowered Accessibility: Allowing users of all technical levels to harness powerful data interactions without needing code or SQL.

Formulas act as the Kernel

Secure Environment

Data Files

Form Content

Data Streams

Functions

Advanced Operations

AI

API Calls

Results in Browser

FI.js formulas extract data from local sources securely; leverage lirbraies of functions, advanced operations, AI, and/or API integrations; and deliver dynamic results to the browser in real time. All operations in FI.js reside securely within your organization's local infrastructure. Data remains protected while formulas extract, process, and deliver insights.

Let's start with this example:
{{ !loan.risk == 'low' }} ? loan.profit - loan.principal * 0.05 : loan.profit

Secure Environment

loan.csv

Profit
Function

! {{ }} - == *
Operations

AI

Treasury API

Results in Browser

Understanding Variables in Formulas

Variables in FI.js formulas represent data fields or properties derived from your data sources. They allow formulas to perform operations based on the values of these fields. Here's a breakdown of how to define and use these variables:

1. Data Sources and Fields

Variables such as loan.open are structured as source.field, where:

To define these variables, ensure that your data sources are correctly configured in your single page application and that each source contains the necessary fields.

When working with formulas in FI.js, it's crucial to understand how to reference your data sources. For detailed instructions on importing and setting up your data, refer to the Setting Up Data Sources section.

2. Metric Properties: Units and Tally

In your formula, variables like units and tally are built-in metric properties used by FI.js.

Defining Units

Units represent the total number of instances of the groupBy field that have been combined or aggregated.

Defining Tally

Tally counts the number of instances within each groupBy field that have a valid result according to the formula.

3. Defining Variables in Formulas

FI.js intuitively connects the data sources required by the formula based on the variable names in formula, for instance

formula: 'tally == units && loan.class in [1, 20] && loan.open > "2024-01-01" && loan.open <= "2024-11-03" ? loan.principal : null',
  groupBy: 'Portfolio',
  ...

FI.js Supported Formula Syntax

Arithmetic Operations (JavaScript)

Logical NOT

The ! operator is known as the logical NOT operator. It's used to invert the boolean value of an operand. Here’s a quick rundown of how it works: Logical NOT (!): If the operand is true, the result is false, and if the operand is false, the result is true.

Conditional (Ternary) Operators (JavaScript)

Operators that take three operands— a condition followed by a question mark ?, then an expression to execute if the condition is truthy, followed by a colon :, and finally the expression to execute if the condition is falsy. Conditional expressions allow for decision-making:

Format:
condition ? expressionIfTrue : expressionIfFalse
Example:
loan.amount > 50000 ? loan.profit : null

Note the condition uses > in this code. The > comparison in our framework and most porgamming environments is an evaluation of two values to determine their relationship. This can involve checking if they are equal, not equal, greater than, less than, greater than or equal to, or less than or equal to each other. Here are the main types of comparison operators:

Another Example:
checking.daysSinceOpen < 90 ? checking.balance : null

In this example, if the checking account has been open for less than 90 days (checking.daysSinceOpen < 90) include the checking account balance in the result (? checking.balance) else include nothing for this account in the final result (: null)

Comparison Operators:

Array Membership (Set Inclusion) Operator

The 'in' operator enables set inclusion testing, allowing you to check if a value belongs to a predefined set:

Format:
value in [set]
Example:
loan.class in [30, 40, 50] ? loan.amount : null //loan.class is 30, 40, or 50
logical NOT operator Example:
loan.class in [30, 40, 50] ? loan.amount : null //loan.class NOT 30, 40, or 50

Date Handling in Formulas

Formulas can process date conditions by calculating day differences:

Format:
dateField > "YYYY-MM-DD", dateField < "MM/DD/YYYY", etc.
Example:
loan.open > "2023-07-15" & loan.open < "2023-12-31" ? loan.profit : null

Truth Propagation with Conditional Locks

Truth propagation allows certain conditions to “lock” all other conditions within the formula to true once any one condition evaluates as true. Use double curly braces {{ }} to define such locks:

Format:
{{ condition }}
Example:
{{ loan.risk == 'high' }} ? loan.principal * 0.05 : loan.principal

Properties in FI.js

In FI.js, Properties are essential elements that define how data is managed, processed, and presented within your single-page applications (SPAs). Properties are categorized into two primary types:

  1. Presentation Properties
  2. Metrics Properties (Units and Tally)

Understanding these categories and their roles will enable you to effectively configure and visualize your data-driven applications.

1. Presentation Properties

Presentation Properties dictate how data is displayed to the end-user. They are primarily used within the presentation section of the appConfig to define the structure and content of the data presentation layers, such as tables or charts.

Structure
const appConfig = {   presentation: {     columns: [       { heading: 'Branch', field: 'branch' },       { heading: 'Type', field: 'class' },       { heading: 'Zip', field: 'zip' },       { heading: 'Birth Year', field: 'birth' },       { heading: 'Gender', field: 'customer.gender' }     ],   }, };

Components

Example

const appConfig = {   presentation: {     columns: [       { heading: 'Branch', field: 'branch' },       { heading: 'Principal', field: 'principal' },     ],   }, };

In this example:

2. Properties

Metrics Properties provide quantitative insights into the data by tracking and summarizing specific aspects. In FI.js, the primary metrics properties are units and tally.

2.1 Units

Units represent the total number of instances of a particular groupBy field that have been combined or aggregated within the application.

Purpose
Example
const appConfig = {
  metrics: {
    units: 'Portfolio',
  },
};

In this example:

2.2 Tally

Tally counts the number of instances within each groupBy field that have a valid result according to the specified formula.

Purpose
Example
const appConfig = {
  metrics: {
    units: 'Portfolio',
    tally: 'Portfolio',
  },
};

In this example:

Logic Behind Units and Tally

  1. Units:
    • Definition: Total instances of the groupBy field.
    • Calculation: Counts all unique groups based on the groupBy field.
    • Use Case: Provides a high-level overview of how data is distributed across different groups.
  2. Tally:
    • Definition: Instances within each group that have valid results as per the formula.
    • Calculation: For each group defined by groupBy, counts the number of records that satisfy the formula.
    • Use Case: Measures the effectiveness or relevance of data within each group, highlighting areas that meet specific criteria.

Combined Use Case

When used together, Units and Tally offer a comprehensive view of your data:

Example Scenario:

This combination allows stakeholders to quickly assess both the distribution and the quality of the data.

Visual Representation

To better understand how Properties function within FI.js, consider the following diagram:

/FI.js-main
          /apps
          /data
            test_loan_data.csv
          /libraries
          /core
          /styles
          ...
        

The diagram illustrates the hierarchical structure of FI.js application, highlighting where different components like presentation, units, and tally fit within the overall framework.

Summary

By effectively utilizing both types of Properties, you can create robust, insightful, and user-friendly applications with FI.js.

Cases

The primary measure of an innovation's usefulness is utility and usefulness. We have included practical banking industry applications. Keep in mind that the FI.js framework is flexible.

FAQ

Q: Do I need extensive JavaScript knowledge?
A: Not necessarily. FI.js has been designed to be useful out of the box and lower the barrier to entry. Even those with limited coding experience can build powerful applications.

Q: How does FI.js handle legacy system integration?
A: FI.js is designed to bridge traditional industries and modern web development. Its extensibility allows you to connect to legacy systems, gradually replacing complexity with clarity.

Q: My formula is not returning any results?
A: Make sure your conditional (Ternary) operators include three operands— a condition followed by a question mark ?, then an expression to execute if the condition is truthy, followed by a colon :, and finally the expression to execute if the condition is falsy.

Incorrect:
loan.open > "2023-07-15" & loan.open < "2023-12-31" ? loan.profit
Correct:
loan.open > "2023-07-15" & loan.open < "2023-12-31" ? loan.profit : null