Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/tutosrive/factus_challenge/llms.txt

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

The bc-v1/ directory contains the Node.js backend for the Factus Challenge project. It is built on Express 4 and requires Node.js 22 or later. The server listens on port 4500 by default (overridable via the PORT environment variable), connects to a PostgreSQL database, and communicates with the Factus electronic invoicing API using OAuth 2.0 tokens managed by the src/auth/token.js module.

Prerequisites

Before running the backend, make sure you have the following installed and available:
  • Node.js ≥ 22 — the server uses the native --env-file and --watch flags introduced in Node 22
  • npm — bundled with Node.js
  • PostgreSQL — a running instance accessible from the machine where the backend will run

Installation

1

Navigate to the backend directory

All backend source code lives under bc-v1/. Move into it before running any commands.
cd bc-v1
2

Install dependencies

Install the five production dependencies with npm:
npm install
The following packages will be installed:
PackageVersionPurpose
axios^1.7.9HTTP client for Factus API requests
express^4.21.2Web framework and router
morgan^1.10.0HTTP request logger middleware
pg^8.13.1PostgreSQL client (pg.Pool)
qs^6.14.0Query-string serialization for OAuth form data
3

Create the .env file

The server loads environment variables from a .env file in the bc-v1/ root using Node’s native --env-file flag. Create the file and populate every variable before starting:
.env
# Server
PORT=4500

# Factus API
url_api=https://api-sandbox.factus.com.co
client_id=your_client_id
client_secret=your_client_secret
email=your_factus_email
password=your_factus_password
# refresh_token is written at runtime — leave blank on first run
refresh_token=

# PostgreSQL
DB_USER=postgres
DB_HOST=localhost
DB_NAME=factus_db
DB_PASSWORD=your_db_password
DB_SSL=false
refresh_token is optional at startup. token.js falls back to the password grant when it is absent and writes the received refresh_token directly into process.env for subsequent refreshes.
4

Start the development server

Run the dev script to start the server with hot reload:
npm run dev
You should see:
Running server in port:  4500
SÍ existe un refresh token   (or NO existe... on first run)

Available npm Scripts

The package.json exposes five scripts:
ScriptCommandDescription
npm startnode ./src/main.jsProduction start — no hot reload, no env-file flag
npm run devnode --env-file .env --watch ./src/main.jsDevelopment mode with hot reload via --watch
npm run factnode --env-file .env ./src/controllers/factura.controller.jsRun factura.controller.js as a standalone script
npm run tokennode --env-file .env --watch ./src/auth/token.jsRun the token module standalone with hot reload
npm testnode --env-file .env --watch ./src/helpers/helpers.mjsRun the helpers module standalone with hot reload
Use npm run dev during development. The --watch flag tells Node.js to automatically restart the process whenever any source file changes, eliminating the need for a separate file-watcher like nodemon.

Route Structure

The Express app mounts three routers, registered in order inside src/main.js:

Page Routes

GET /Served by page.routes.jspage.controller.js. Returns the frontend entry point.

Invoice Routes

/factura*Served by factura.routes.js. Handles all Factus API invoice operations (list, get, create, download, delete).

Database Query Routes

/get-data, /add-data, /get-join, /update-data, /deleteServed by querys.routes.js. Generic CRUD endpoints backed by pg.Pool.

Full Route Map

MethodPathRouter fileDescription
GET/page.routes.jsServe frontend
GET/facturafactura.routes.jsList recent invoices
GET/factura/:numberfactura.routes.jsGet one invoice by number
GET/factura-download/:numberfactura.routes.jsDownload invoice PDF (base64)
POST/facturafactura.routes.jsCreate and validate a new invoice
DELETE/factura/:reference_codefactura.routes.jsDelete an unvalidated invoice
GET/get-data/:tablequerys.routes.jsSelect all rows from a table
POST/add-data/:tablequerys.routes.jsInsert a row into a table
POST/get-joinquerys.routes.jsExecute a raw JOIN query
PUT / PATCH/update-data/:table/:property/:valuequerys.routes.jsUpdate rows matching a column value
DELETE/delete/:table/:property/:valuequerys.routes.jsDelete rows matching a column value

CORS Configuration

The backend applies a manual CORS middleware in main.js before any route is handled. It uses a wildcard origin so that the frontend can be served from any host during development:
app.use((req, res, next) => {
  res.header('Access-Control-Allow-Origin', '*');
  res.header('Access-Control-Allow-Methods', 'GET,POST,PUT,DELETE,PATCH');
  res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization');
  next();
});
The Authorization header is explicitly allowed because every Factus API proxy request includes a Bearer token forwarded from the client.

src/main.js — Full Source

src/main.js
import express from 'express';
import querys_route from './routes/querys.routes.js';
import morgan from 'morgan';
import factura_route from './routes/factura.routes.js';
import token from './auth/token.js';
import page_route from './routes/page.routes.js';

// Principal app
const app = express();
const port = process.env.PORT || 4500;

// Generar token de acceso
token();
// Escuchar puerto (localhost:4500)
app.listen(port, () => {
  console.log('Running server in port: ', port);
});

app.use((req, res, next) => {
  res.header('Access-Control-Allow-Origin', '*');
  res.header('Access-Control-Allow-Methods', 'GET,POST,PUT,DELETE,PATCH');
  res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization');
  next();
});

// Para que la API comprenda los "POST" con body JSON
app.use(express.json());

// "Debug", mostrar solicitudes realizadas
app.use(morgan('dev'));

app.use([querys_route, factura_route, page_route]);

Build docs developers (and LLMs) love