Skip to main content

AppConstants Reference

Introduction​

AppConstants is a static class that centralises every application-wide constant into a single, predictable location. Instead of scattering magic numbers, URLs, and configuration values across the codebase, every library and application reads them from AppConstants. This guarantees consistency: when the backend URL changes, it changes in one place; when a tax rate is updated, every price calculation picks it up automatically.

Values in AppConstants come from two sources:

  1. Hard-coded defaults -- values that are inherent to the business domain (tax rates, printer widths, the application name) and do not vary between environments.
  2. Runtime config (config.js) -- required for URLs, sandbox flags, version, production flag, analytics ID. Loaded before Angular; each deployment serves its own config.js. Same build for all environments. If missing or incomplete, the app throws.
import { AppConstants } from '@unpispas/upp-defs';

When to use AppConstants​

Use AppConstants whenever you need a value that:

  • Is shared across multiple files, libraries, or features.
  • Might change between environments (development vs production).
  • Represents a business rule (tax rates, invoice limits, cache durations).
  • Is an external key or identifier (API keys, Firebase VAPID key, OAuth client ID).

Never hard-code these values locally. If you find yourself writing const BASE_URL = 'https://...' or const VAT = 21, use the corresponding AppConstants getter instead.


Application identity​

These constants identify the application itself. They are used in headers, about screens, version checks, and build metadata.

GetterTypeValue / SourceDescription
Appnamestring'UnPisPas'The display name of the application. Used in UI headers, log prefixes, and TicketBAI registration.
Versionstringconfig.appVersionSemantic version string. Appears in the about screen, is sent to the backend during sync, and is reported in TicketBAI submissions.
Buildstring'0'Legacy build number from before the Nx migration. Kept for backward compatibility but no longer incremented.
isProductionbooleanconfig.productionWhether the current deployment targets production. Guards behaviours like verbose logging, sandbox APIs, and development-only UI.

Why these exist: The application needs a single source of truth for its own identity. The version string, in particular, must match exactly between the frontend and the TicketBAI fiscal submissions, so reading it from one place prevents mismatches.

Example​

if (!AppConstants.isProduction) {
console.warn(`[DEV] Running ${AppConstants.Appname} v${AppConstants.Version}`);
}

URLs​

The URL constants provide full endpoint addresses. config.js must define appPath, apiPath, wsrPath, qraPath, and domain. appRoute, apiRoute, wsrRoute, and qraRoute are optional and default to '/'.

GetterTypeDescription
baseURLstringBackend REST API base URL. Built from config.apiPath + config.domain + config.apiRoute.
thisURLstringCurrent application (frontend) URL. Built from config.appPath + config.domain + config.appRoute. POS chrome, sharing, and other “this app” links.
qraURLstringGuest QR SPA public base. Built from config.qraPath + config.domain + config.qraRoute. Same role as PHP AppConstants::QraUrl(). Table stickers (QrCode.QrCodeUrl) and guest deep links use this, not thisURL. Throws if qraPath is missing.
restURLstringDevice WebSocket relay REST base (POST /send). Built from config.wsrPath + config.domain + config.wsrRoute — not the PHP API host.
apppathstringFrom config.appPath -- the subdomain portion (e.g. 'app.nx.').
appRoutestringFrom config.appRoute (default '/'). Public path of this SPA's config.js (POS vs QRA). Distinct from qraURL, which is the guest product URL even when the POS bundle is running.
domainstringFrom config.domain -- the base domain for all subdomains (e.g. 'unpispas.com').

config.js schema for URLs: appPath, apiPath, wsrPath, qraPath, domain, appRoute, apiRoute, wsrRoute, qraRoute. AppConstants constructs full URLs from these fragments. | uploadPath | string | 'upload/' -- relative path appended to baseURL for file uploads (images, attachments). |

Why these exist: A POS system talks to multiple backend endpoints (REST API, WebSocket relay, file uploads). Centralising the base URLs ensures every service call targets the correct server for the current environment. restURL must hit the WSR gateway (wsr.*), never Slim (api.*).

How URLs are constructed​

baseURL = "https://" + apiPath + domain + (apiRoute ?? "/")
thisURL = "https://" + appPath + domain + (appRoute ?? "/")
qraURL = "https://" + qraPath + domain + (qraRoute ?? "/")
restURL = "https://" + wsrPath + domain + (wsrRoute ?? "/")

For example:

https://    api.nx.      unpispas.com   /
^scheme ^apiPath ^domain ^apiRoute

https:// wsr.nx. unpispas.com /
^scheme ^wsrPath ^domain ^wsrRoute

Examples​

// Build a full upload URL for an image stored in the database
const imageUrl = AppConstants.baseURL + AppConstants.uploadPath + filename;
// e.g. "https://api.unpispas.com/upload/photo_12345.jpg"

// Build the avatar URL for a product
const avatarUrl = AppConstants.baseURL + 'photo/avatar?size=128&name=' + encodeURIComponent(name);

// Check if an image URL belongs to our backend
const isOwnImage = imageUrl.startsWith(AppConstants.baseURL);

Tax rates​

Spain has three VAT (IVA) rates. These constants encode the current legal rates and are used by PriceInfo, the ticket system, and any component that displays or calculates prices.

GetterTypeValueDescription
TaxRate1number4Super-reduced VAT rate (4%). Applies to basic necessities (bread, milk, books, medicine).
TaxRate2number10Reduced VAT rate (10%). Applies to food, water, hospitality, passenger transport, and similar categories.
TaxRate3number21General VAT rate (21%). The default rate for most goods and services.
defaultTaxRatenumber10 (= TaxRate2)The fallback tax rate when a product or line item does not specify one. Set to the reduced rate because the primary use case is hospitality (restaurants, bars).

Why these exist: Tax rates are mandated by Spanish law and appear in dozens of calculations across the system -- product prices, ticket totals, discount breakdowns, TicketBAI submissions, and printed receipts. Having them as named constants prevents errors (nobody accidentally writes 22 instead of 21) and makes future rate changes a single-line edit.

Example​

// In PriceInfo, the default tax rate is used when no rate is provided
const price = new PriceInfo(50); // 50 EUR at defaultTaxRate (10%)

// Explicitly use the general rate
const price21 = new PriceInfo(100, AppConstants.TaxRate3); // 100 EUR at 21%

// A product view falls back to the default rate when the product has no rate set
const rate = product.taxrate || AppConstants.defaultTaxRate;

Timings and thresholds​

These constants control time-based behaviours and search sensitivity throughout the application.

GetterTypeValueDescription
CacheExpirationnumber432 000 000 (5 days in ms)Maximum age of cached session data before it is considered stale and discarded. When the sync module recovers stored data from IndexedDB, it checks whether the data is older than this threshold. If it is, the cache is invalidated and a full sync is triggered.
recentMsnumber28 800 000 (8 h)Time window for considering tickets "recent". A ticket is "recent" if now - reference < recentMs, where reference is updated or (fallback) created.
MainRefreshnumber500Interval in milliseconds for the main sync refresh tick. The sync module uses setInterval with this value to periodically check and push pending changes. 500ms gives near-real-time sync without overwhelming the system.
SearchThresholdnumber80Minimum fuzzy-search score (0-100) for a result to be considered a match. Used by the product search in the catalog view. A score of 80 means only close matches appear, reducing noise.
invoiceMaxPricenumber3000Maximum price (in EUR) for a simplified invoice under Spanish regulation. When a ticket exceeds this amount, the system requires a full invoice with the customer's tax ID. This is a legal requirement, not a business preference.

Why these exist: Each of these values encodes either a business rule or a UX decision that affects multiple parts of the system. Centralising them makes it easy to tune behaviour (e.g. change the search sensitivity) without hunting through the codebase.

Examples​

// Sync module: check if cached data is still fresh
const elapsed = Date.now() - metadata.timestamp;
if (elapsed > AppConstants.CacheExpiration) {
console.warn('[STORAGE] Stored data are outdated!');
return false;
}

// Ticket object: determine if a ticket is recent (current shift)
get isRecent(): boolean {
const ref = this.updated || this.created;
return !!ref && (Date.now() - ref.getTime()) < AppConstants.recentMs;
}

// Ticket view: check if a full invoice is required
get requiresInvoice(): boolean {
return this.priceinfo.val >= AppConstants.invoiceMaxPrice;
}

// Product catalog: filter search results
const results = search.doSearch(criteria, products, AppConstants.SearchThreshold);

Printing defaults​

These constants configure thermal receipt printing, the primary output format for a POS system.

GetterTypeValueDescription
defaultPrintWidthnumber58Default thermal-printer paper width in millimetres. 58mm is the standard width for most POS receipt printers.
defaultPrintFontnumber12Default font size in pixels for printed ticket text. Balanced for readability on 58mm paper.
thumbnailWidthnumber140Pixel width for image thumbnails (product images, logos). Used when resizing images for display in the catalog grid.
thumbnailColumnsnumber24Column count used for thumbnail grid layouts. Determines how many characters fit across a receipt when rendering grid-based content.

Why these exist: Receipt printers have strict physical constraints. Hard-coding 58 in every print-related component would scatter knowledge about the hardware across the codebase. These constants let the printing subsystem adapt if a different printer width is needed in the future.


Language​

GetterTypeValueDescription
defaultLanguagestring'es'Fallback language code when the browser locale is not supported. Spanish is the default because the primary market is Spain.

Why this exists: The language service in upp-base uses this as the ultimate fallback. If a user's browser reports a language that the application does not support, the UI falls back to Spanish rather than showing raw translation keys.


Service Worker​

AppConstants does not decide guest vs POS. Those are separate Angular apps.

unpispas-qra registers firebase-messaging-sw.js in its own AppModule, with scope: AppConstants.appRoute (this bundle's config.js) and enabled false on Cordova (http://localhost/). unpispas-pos does not register a service worker. Session mode (stateService.Access) is unrelated to which worker file to load.


TicketBAI / Verifactu (Spanish fiscal compliance)​

Spanish legislation context

TicketBAI es un sistema de facturacion obligatorio en el Pais Vasco (Bizkaia, Gipuzkoa, Araba) que requiere que todo software de facturacion se registre ante las haciendas forales con licencias, nombres de desarrollador y NIFs especificos por territorio. Verifactu (SII) es el equivalente para el resto de Espana.

These constants manage the registration data required by the Basque Country's TicketBAI fiscal compliance system. Every software that generates invoices in the Basque Country must be registered with the regional tax authority and must include its licence code, developer identity, and NIF in every fiscal submission.

Getter / MethodTypeDescription
TicketBaiSandboxbooleanWhether to use the TicketBAI sandbox (test) environment. From config.ticketbai_sandbox. When true, all TicketBAI methods return test credentials instead of production ones.
VeriFactuSandboxbooleanWhether to use VeriFactu sandbox mode. From config.verifactu_sandbox.
SoftwareDeveloperNamestringRegistered software developer legal name used in fiscal identification metadata.
SoftwareDeveloperTaxIdstringTax ID (NIF/CIF) for the registered software developer.
SoftwareDeveloperFiscalstringFiscal address of the registered software developer (issuer on license invoices).
SoftwareSystemIdstringSoftware system identifier used in fiscal compliance payloads.
TicketBaiAppname(region)stringReturns the registered application name for the given region. The name is registered with the regional tax authority and must match exactly in submissions.
TicketBaiAppvers(region)stringReturns the application version string for TicketBAI. Returns AppConstants.Version if a region is provided, '0.0.0.0' otherwise (indicating no TicketBAI region is configured).
TicketBaiLicense(region)stringReturns the TicketBAI software licence code for the region. Each region issues a unique licence code during the registration process.
TicketBaiDeveloper(region)stringReturns the registered developer name for the region.
TicketBaiNIF(region)stringReturns the developer's NIF (tax identification number) for the region.

Supported regions: 'Bizkaia', 'Gipuzkoa', 'Araba'.

How it works internally: The class maintains a private TicketBaiRegistry object with two keys: PRD (production) and DEV (development/sandbox). Each contains region-specific registration data. The public methods select the correct environment based on TicketBaiSandbox and then look up the requested field for the given region.

Example​

// When generating a TicketBAI-compliant invoice for Bizkaia
const region = 'Bizkaia';
const submission = {
licence: AppConstants.TicketBaiLicense(region),
appName: AppConstants.TicketBaiAppname(region),
appVersion: AppConstants.TicketBaiAppvers(region),
developer: AppConstants.TicketBaiDeveloper(region),
developerNIF: AppConstants.TicketBaiNIF(region),
sandbox: AppConstants.TicketBaiSandbox
};

// In development, TicketBaiSandbox is true, so these return test credentials
// In production, they return the real registered credentials

API keys​

These constants hold external API keys and identifiers for third-party services.

GetterTypeDescription
googleApiKeystringGoogle Maps / Geocoding API key. Used by the geocode service in upp-base to resolve addresses to coordinates and vice versa.
GoogleMapKeystringGoogle Maps Android SDK key. Used when the application runs as a native Android app via Capacitor.
googleOAuth2KeystringGoogle OAuth 2.0 client ID. Used for "Sign in with Google" flows.
GoogleAnaliticsstringGoogle Analytics tracking ID. From config.googleAnalytics, so it can differ between environments (e.g. a separate analytics property for staging).
FCMVapidKeystringFirebase Cloud Messaging VAPID key for web push notifications. Required to subscribe the browser to push notifications from Firebase.

Why these exist: API keys must be consistent across the application. If the geocode service and the map component used different Google API keys, quota tracking would be split and billing would be unpredictable. Centralising them also makes key rotation straightforward -- update one constant, rebuild, and every consumer picks up the new key.

Example​

// Geocode service uses the Google API key
const geocodeUrl = `https://maps.googleapis.com/maps/api/geocode/json?address=${encodeURIComponent(address)}&key=${AppConstants.googleApiKey}`;

// Firebase push notification subscription
const subscription = await messaging.getToken({ vapidKey: AppConstants.FCMVapidKey });

Common patterns​

Reading config-dependent values​

AppConstants reads from config.js (required). If config is missing or incomplete, it throws:

// In AppConstants
public static get baseURL(): string {
const c = this.Config();
return 'https://' + c.apiPath + c.domain + (c.apiRoute ?? '/');
}

public static get restURL(): string {
const c = this.Config();
return 'https://' + c.wsrPath + c.domain + (c.wsrRoute ?? '/');
}

You never import config directly outside of upp-defs. Always go through AppConstants.

Combining URL constants​

The most common pattern in the codebase is building full URLs by concatenating base URLs with path segments:

// File upload
const url = AppConstants.baseURL + AppConstants.uploadPath + filename;

// Avatar generation
const url = AppConstants.baseURL + 'photo/avatar?size=128&name=' + encodeURIComponent(name);

// Catalog JSON endpoint
const url = AppConstants.baseURL + 'catalog/' + resourcePath;

// Catalog product images (demo catalogs)
const imageUrl = AppConstants.baseURL + 'resources/catalog/images/' + filename;

Conditional behaviour by environment​

if (AppConstants.isProduction) {
// Production-only: register analytics, enable error reporting
} else {
// Development-only: verbose logging, sandbox APIs
}

Using tax rates with PriceInfo​

const price = new PriceInfo();
price.Add(menuPrice, AppConstants.TaxRate2); // Food at 10%
price.Add(beveragePrice, AppConstants.TaxRate2); // Beverage at 10%
price.Add(serviceCharge, AppConstants.TaxRate3); // Service at 21%