SwiftInvoicePro — Security & Controls Whitepaper
Apex Flow Technology Ltd · Company No. 17347345 · England & Wales Self-authored. Version 1.8 · 20 August 2026 · Next review: February 2027
This document describes controls that are currently implemented in the product. It is not a third-party audit, certification, or penetration test report, and it does not claim to be one.
1. Entity and scope
| Field | Value |
|---|---|
| Legal entity | Apex Flow Technology Ltd |
| Company number | 17347345 (England & Wales) |
| Registered office | 29 Railway Road, Rhoose, Barry, Wales, CF62 3FE |
| Product in scope | SwiftInvoicePro — corporate folio aggregation and invoice generation |
| Security contact | natromrich@googlemail.com |
| Data controller | The hotel or hotel group. Apex Flow acts as processor. |
Out of scope: the customer's own PMS, POS, and finance systems; any network or endpoint the customer operates.
2. Data handling and integration security
- Data minimisation profile. PMS integration is read-only parameter mapping. We request only the fields required for corporate folio and ledger reconciliation — transaction codes, amounts, tax components, business dates, and the corporate account reference. Nothing is written back to the PMS at any point.
- PII isolation. Guest names, personal contact details, and card data are filtered out at the ingestion layer before aggregation. No guest PII is permanently written to the SwiftInvoicePro database.
- Encryption. All traffic between the hotel PMS or marketplace and SwiftInvoicePro is protected with TLS 1.3, terminated at the edge. Data at rest in the production database is encrypted with AES-256 by the managed database provider.
- Ephemeral in-memory processing. Ledger cross-matching runs inside a per-request isolate. Transaction lines are parsed, reconciled against the corporate account map, and released with the request context. There is no long-lived server state and no intermediate write to cache or disk.
3. Multi-tenant architecture and boundary protection
- Logical separation of customer data. SwiftInvoicePro is a cloud-native multi-tenant application. Every tenant-scoped table carries
organization_idoruser_id, and isolation is enforced at the database query layer by PostgreSQL Row Level Security — not in application code — so a mistaken or compromised client cannot widen its own scope. - Role-based access control. Administrative surfaces are gated by explicit role tiers. Roles are stored only in
user_rolesand read through thehas_rolesecurity-definer function, which prevents client-side privilege escalation and blocks horizontal access across properties within a group. - Cryptographic tenant isolation on inbound integrations. Each property's PMS webhook endpoint is addressed per tenant (
/api/public/webhooks/opera/<organizationId>) and verified with an HMAC-SHA256 signing key derived per organisation from a root key held in the server vault. Tenancy is taken from the verified URL path, never from the request body, so a caller holding one property's key cannot sign a payload that writes billing lines against another property. The legacy shared-secret endpoint no longer accepts billing writes. Signature verification is paired with timestamp and nonce checks to reject replayed deliveries. - Resource throttling on abusable surfaces. Outbound transactional email is restricted to an explicit template allowlist, attachment links are validated as belonging to the calling account's own storage prefix, free-text fields are length-clamped, and every send is attributed to the authenticated sender and counted against a per-account daily cap. The endpoint cannot be used as an open relay or as an amplification path against third parties.
- Server-vault credential protection for automation. Scheduled background workers (anomaly scanning, authorization-window settlement) authenticate with a server-only credential read from the managed secret vault at invocation time. The public anon/publishable key is explicitly rejected, and comparisons are constant-time. No automation credential exists in client bundles, source control, or scheduler definitions in plaintext.
- Enforcement at the network edge. Signature verification, tenant resolution, credential checks, and throttling all execute in the edge runtime that terminates the request, before any database session is opened — a rejected caller never reaches Postgres.
- Integration token lifecycle. Credentials issued for a shadow pilot are scoped to that pilot and carry a hard 60-day expiry, so a pilot credential cannot persist unmonitored past the validation window. A pilot is terminated at any time by revoking that single credential. Automated rotation on a fixed schedule is a commitment for first paid deployment, not a control in place today.
4. Vulnerability management and continuous monitoring
- Dependency scanning. Application dependencies are scanned automatically against known CVEs by a continuous-integration job (
.github/workflows/dependency-audit.yml) that runs on every push and pull request, on a weekly schedule, and on demand. The job executesscripts/audit-dependencies.mjsagainst the committed lockfile and fails the build on any high or critical finding, so a vulnerable dependency cannot reach a release unnoticed. Each run publishes a retained JSON report giving an auditable scan history. Findings are triaged on discovery; the affected package is upgraded and the lockfile regenerated before the next deploy. - Software Bill of Materials. The same continuous-integration job generates a CycloneDX 1.5 SBOM (
scripts/generate-sbom.mjs) from the committed lockfile on every run, listing each dependency's name, resolved version, package URL, distribution artefact hash, and licence where the package declares one. The SBOM is retained alongside the scan report as a build artefact and is supplied to customers, prospects, and reviewers on request; it is not published publicly. It is generated from the lockfile rather than hand-maintained, so it cannot drift from what is actually deployed. - Continuous automated code and configuration scanning. An automated scanning platform (Aikido) runs continuously across the codebase and its infrastructure configuration, covering static application security testing (SAST), software composition analysis, secrets detection, and infrastructure-as-code and cloud posture checks. Findings surface to the operator as they are raised and are triaged on discovery. This is automated analysis, not a penetration test: no live target is attacked and no third party attests to the result.
- Adversary-simulation regression suite. A test suite written from the attacker's perspective runs in continuous integration on every change (
src/lib/security/adversary-simulation.test.ts). It comprises 63 tests across five classes — webhook forgery and replay, tenant-identifier manipulation, privilege escalation through server functions, post-authentication open redirect, and credential exposure in the client bundle. Each test asserts that a specific attack fails, so weakening a control breaks the build rather than passing silently. As of 18 August 2026 all 63 pass. The suite covers application-layer gates; database-layer isolation is covered separately by the automated post-migration validation described in §2. - Patch management targets. We target production deployment of critical security patches within 48 hours of a fix being available, and remediation of high and medium findings within a 30-day cycle. These are operating targets, not a contractual SLA. A binding patch SLA can be scoped and agreed as part of a commercial agreement.
- Audit logging. Billing, invoice-usage, and inbound webhook events are written to a central
audit_logsstore recording actor, action, resource type and identifier, IP address, user agent, and timestamp. The log is append-only in practice: no update or delete path is exposed to any client, authenticated users can read only their own rows, and writes are made server-side only. Extending coverage to authentication attempts and role changes is on the roadmap and is not claimed as a control in place today. - Incident response framework. A written incident response plan governs suspected security events, defining severity tiers, the named responder, containment and evidence-preservation steps, recovery, customer communication, and post-incident review. See
docs/INCIDENT-RESPONSE-PLAN.md, available to reviewers on request. - Breach notification. On confirmation of a personal-data breach affecting a customer, we notify the affected controller without undue delay and, where feasible, within 72 hours of becoming aware, with the facts known at that time. Notification is not withheld pending a complete investigation.
5. Endpoint security and operational governance
Apex Flow Technology Ltd is a single-operator entity. The controls below describe the actual operating practice today; controls that are not yet in place are listed as planned rather than implied.
In place today
- Full-disk encryption. The development workstation holding local application code uses hardware-backed full-disk encryption (FileVault/BitLocker class), with automatic screen lock.
- Multi-factor authentication. MFA is enforced on every account that can reach infrastructure, the code repository, the deployment pipeline, and operational communication channels. Authentication is authenticator-app (TOTP) based.
- Secure credential storage. System passwords, API tokens, and cloud environment secrets are held only in the server-side environment vault and a dedicated encrypted password manager. No credential is committed to source control, pasted into documents, or shared over chat or email.
- Production / non-production separation. Development and testing use non-production credentials and non-production endpoints. Local development does not target production database configuration, and production deployment is a separate, explicitly authenticated action.
- Browser hardening headers. Every response leaving the edge worker — pages and API responses alike — carries
Content-Security-Policy(withframe-ancestors 'none',object-src 'none',base-uri 'self'andform-action 'self'),Strict-Transport-Security(2 years, subdomains, preload),X-Content-Type-Options,X-Frame-Options,Referrer-Policy,Permissions-PolicyandCross-Origin-Opener-Policy. These are applied centrally in the worker entry point, so no route can ship without them. - Abuse throttling on unauthenticated endpoints. The public contact, interest and pilot-request endpoints are rate-limited per caller (hashed source address, never a stored IP) using an atomic database counter rather than per-process memory, so the limit holds across concurrent edge isolates. Machine-to-machine billing endpoints remain protected by per-tenant HMAC signatures with replay and timestamp rejection, as described in section 3.
Planned, not yet in place
- In-product multi-factor authentication for customer accounts. Committed for delivery before the first production pilot goes live, and scoped as part of the pilot agreement. It is not offered today because there are no production tenants yet. The operator-side MFA described above is a separate, already-implemented control.
- Hardware security keys (FIDO2/WebAuthn) for deployment and provider console access, replacing TOTP as the second factor.
- Container-sandboxed local development workloads isolating testing from all other local state.
- Formal mobile device management (MDM) with enforced device policy and remote wipe.
These gaps are a function of company stage. Each is in scope to be closed as part of a commercial engagement and can be prioritised against a customer's procurement requirements.
6. Architecture
- Edge/application tier — TanStack Start application served from Cloudflare's edge network. Server functions execute in per-request isolates with no long-lived server state between requests.
- Data tier — managed PostgreSQL (Supabase via Lovable Cloud), provisioned in EU-West (Ireland).
- Aggregation tier — folio aggregation runs in a stateless handler. Guest PII and transaction lines are held in memory for the life of the request only and are not written to relational tables, cache, or disk.
- Payments — Stripe-hosted. No card PAN, CVV, or expiry ever reaches Apex Flow systems.
7. Data flows
PMS / POS --(read-only, HMAC-signed webhook or pull)--> Edge handler
|
in-memory aggregation + validation
|
+-------------------------------+------------------+
| |
invoice document returned invoice metadata persisted
(PDF/A stream to caller) (org-scoped, RLS-enforced)- Ingestion is read-only. Nothing is written back to the property management system at any point. A pilot is terminated by revoking a single credential.
- Validation. Inbound payloads pass a schema validator that enforces types and UUID formats, strips angle brackets from free-text fields, and caps batch size.
- Aggregation. PMS, POS, and corporate-ledger lines are joined in a single request context.
- Return and flush. The rendered document is streamed to the caller; the request context is released for garbage collection.
8. What is stored, and what is never stored
Stored (organization-scoped, RLS-enforced): organization and membership records; user account identifiers and authentication metadata; invoice and folio records the customer asks us to keep; corporate account profiles; audit and webhook event logs; website contact and pilot enquiries.
Never stored: card primary account numbers, CVV, or expiry; raw guest PII from aggregation batches beyond the life of the request; credentials belonging to a customer's PMS in plaintext.
9. User access limits
- Tenancy is expressed by
organizationsandorganization_members. Every tenant-scoped table carriesorganization_idoruser_id. - Row Level Security is the isolation boundary. Access is decided in the database, not the application, so a mistaken or compromised client cannot widen its own scope.
- Policy predicates call
SECURITY DEFINER,STABLE,search_path = publicgatekeeper functions:is_org_member,is_org_admin,is_hotel_manager, andhas_role. They take explicit arguments, return booleans only, and expose no row data. - Roles are never stored on profile tables. They live only in
user_rolesand are read throughhas_role, which prevents client-side privilege escalation. - Default privileges on the
publicschema have been revoked fromanonandauthenticated. Every table holds only the commands its own policies permit, for only the roles those policies name. New tables start with zero access until their migration grants it. service_rolebypasses RLS and is used exclusively by server-side code after the caller has been verified. It is never exposed to the browser.- Membership cannot be self-assigned from a client:
organization_membersis SELECT-only for authenticated users; writes are service-role.
10. Secrets management
- API keys, webhook secrets, and provider credentials are held in server-side environment vaults and read inside request handlers only.
- No secret carries a client-visible (
VITE_) prefix; client bundles contain publishable keys only. - Webhook authenticity is verified with HMAC-SHA256 against a per-tenant shared secret using a timing-safe comparison, with a short-lived nonce cache to reject replays.
11. Error handling and failure isolation
- All errors are normalised to safe codes (
VALIDATION_FAILED,UNAUTHORIZED,AGGREGATION_FAILED). Raw SQL text, stack frames, and database error strings are not returned to clients. - A global error middleware wraps every server function; catastrophic server-render errors are normalised before the response leaves the edge.
- Logs are scrubbed of personal data before forwarding.
- Failure isolation: during a shadow pilot the validation layer runs alongside the existing process. The PMS ledger remains authoritative, and a fault in our layer cannot affect the guest path or PMS operations.
- Duplicate webhook delivery is idempotent; replays do not produce duplicate invoices.
12. Automated security validation
security_validation_report() (service-role only) inspects every table in public and reports: tables without RLS enabled (critical); tables with privileges but no policies (warning); and tables where anon or authenticated hold privileges wider than their policies allow (warning). Runs are written to security_validation_runs with counts, pass/fail, and operator, giving an auditable history. Any critical finding blocks release.
Cadence: after every migration touching public, and before any enterprise security review or pilot go-live.
13. Retention
| Record | Retention |
|---|---|
| Contact and pilot enquiries | Up to 12 months from last contact, then deleted |
| Pilot accounts | Duration of the pilot; deleted or anonymised within 30 days of pilot end |
| Tokenised card references for incidentals | 2–4 hours after checkout, then purged |
| Invoices and folio records | For the period the customer requires for tax and accounting |
| Aggregation batch PII | Not retained — request lifetime only |
Data subjects may request access, correction, export, deletion, or withdrawal of consent at natromrich@googlemail.com. We aim to respond within 30 days.
14. Sub-processors
| Sub-processor | Purpose | Region |
|---|---|---|
| Cloudflare, Inc. | Edge hosting, DNS, TLS termination | Global edge |
| Supabase (via Lovable Cloud) | Managed Postgres, authentication, storage | EU-West (Ireland) |
| Stripe Payments Europe, Ltd. | Payment processing | EU / Global |
| Resend | Transactional email delivery | EU / US |
Invoice and account records are stored in a single EU region. Where a sub-processor necessarily processes personal data outside the UK or EEA, the transfer is made under the EU Standard Contractual Clauses, supplemented by the UK International Data Transfer Addendum for UK-originating data. Apex Flow is UK-established and does not self-certify under the EU–US Data Privacy Framework.
15. Inherited infrastructure compliance — and its limits
Our infrastructure providers maintain their own independent assurance programmes:
- Cloudflare — SOC 2 Type II and ISO 27001 for its platform.
- Supabase / AWS EU-West (Ireland) — SOC 2 and ISO 27001 for the managed platform and underlying cloud.
- Stripe — PCI DSS Level 1. No card PAN touches Apex Flow systems.
These certifications cover the providers' platforms. They do not extend to the SwiftInvoicePro application layer, and Apex Flow does not claim them as its own. Apex Flow Technology Ltd is not currently SOC 2, ISO 27001, or PCI DSS certified, and holds no completed third-party penetration test. See the accompanying bridge letter for the plan and trigger for a SOC 2 Type 1 engagement.
16. Incident and vulnerability handling
- Report a suspected vulnerability or incident to natromrich@googlemail.com. We acknowledge within one business day.
- Breach notification timing and the incident response framework are set out in Section 4.
- We do not currently operate a paid bug bounty. Good-faith research is welcome and will not be pursued legally where it avoids service disruption and access to other tenants' data.
17. Known accepted findings
enterprise_settingsandpublic_rate_limitshave RLS enabled and no policies, and hold noanon/authenticatedprivileges. This is intentional: both tables are service-role only.- The database linter flags the gatekeeper functions as
SECURITY DEFINERcallable by signed-in users. This is required — RLS policies call them on behalf of the caller. They accept explicit arguments, return booleans only, and expose no row data.
18. Related documents
- Bridge letter (bootstrapped-vendor transparency statement) — available on request.
- CAIQ Lite self-assessment responses — available on request under NDA.
- Art. 28 Data Processing Agreement — available on request.
docs/SECURITY-ARCHITECTURE.md— internal architecture register.docs/DATABASE-MIGRATION-STANDARD.md— mandatory structure for new tenant-scoped tables.docs/INCIDENT-RESPONSE-PLAN.md— incident severity tiers, response steps, and notification clock.