Skip to content

Latest commit

 

History

History
83 lines (59 loc) · 7.22 KB

File metadata and controls

83 lines (59 loc) · 7.22 KB

System Architecture

This document provides a detailed breakdown of the TradeOps platform architecture, network security design, and deployment configuration.


1. Architectural Overview

TradeOps is designed around a strict separation of concerns, partitioning public-facing features from sensitive back-office management interfaces. The platform consists of two principal environments: the Public Surface and the Private Surface.

1.1 Deployment Topology

The platform utilizes a split deployment architecture where public and administrative routing domains are physically separated at the hosting layer.

       PUBLIC SERVICE (Internet-facing)                   PRIVATE SERVICE (VPN Mesh only)
     ┌───────────────────────────────────┐             ┌───────────────────────────────────┐
     │ Vercel Project A: Public Website  │             │ Vercel Project B: Admin Dashboard │
     │ domain: yourdomain.com            │             │ domain: admin.yourdomain.com      │
     └─────────────────┬─────────────────┘             └─────────────────┬─────────────────┘
                       │ HTTPS POST                                      │ HTTPS API Calls
                       ▼                                                 ▼
     ┌───────────────────────────────────┐             ┌───────────────────────────────────┐
     │ Railway Service A: Public API     │             │ Railway Service B: Admin API      │
     │ APP_MODE = public                 │             │ APP_MODE = admin + Tailscale Node │
     │ (Admin endpoints return 404)      │             │ (Full routes, unreachable publicly)│
     └─────────────────┬─────────────────┘             └─────────────────┬─────────────────┘
                       │                                                 │
                       └────────────────────────┬────────────────────────┘
                                                ▼
                              ┌───────────────────────────────────┐
                              │     Neon Serverless PostgreSQL    │
                              │         (Single Shared DB)        │
                              └───────────────────────────────────┘

2. Split-Deployment Strategy (APP_MODE)

A single, unified backend repository (Python 3.11 with FastAPI) is deployed for both the public and admin backend instances. Route exposure is controlled via the APP_MODE environment variable at startup:

  • APP_MODE=public: Only public routes are registered in the FastAPI application (e.g., /health, /api/contact). Administrative routes (e.g., /auth/*, /sales/*, /invoices/*) are completely omitted from the router stack. Attempts to hit these endpoints return an HTTP 404 Not Found rather than 401 Unauthorized or 403 Forbidden, masking the administrative surface area from web scanners.
  • APP_MODE=admin: The full suite of API endpoints is registered. The instance is deployed inside a private network, and access is restricted to authenticated VPN clients.

3. Network Isolation with Tailscale VPN

Rather than securing the admin dashboard and API behind a standard web login wall exposed to the public internet, TradeOps relies on network-level access control via a Tailscale VPN mesh.

3.1 VPN Security Mechanics

  1. No Public Ingress: The Railway instance running the administrative backend does not expose a public domain or port to the internet. The backend runs as a Tailscale sidecar container, enrolling itself directly into the private Tailscale network.
  2. Access Control: Only enrolled devices (e.g., the Client's desktop/laptop devices) configured with active Tailscale authentication can resolve and route traffic to the admin API or admin frontend. Non-enrolled devices experience connection timeouts.
  3. Defense Against Brute-Forcing: Because the login page is invisible to the public internet, the threat of credential stuffing, DDoS, and brute-force attacks against administrative interfaces is eliminated.

4. Local On-Premise Database Migration Path

The database configuration supports a migration path from cloud-hosted PostgreSQL (Neon) to an on-premise PostgreSQL instance situated on a physical Linux PC inside the Client's office.

4.1 Dynamic-IP Resolution over VPN

Standard broadband ISP services assign dynamic IP addresses that cycle periodically. This makes traditional IP whitelisting impractical for connecting the cloud backend (Railway) to the local database.

TradeOps overcomes this constraint by utilizing Tailscale:

  • The local Linux server runs a persistent Tailscale daemon, assigning it a permanent IP address within the 100.64.0.0/10 overlay range (e.g., 100.64.12.34).
  • The database daemon is configured to listen on all interfaces (0.0.0.0) but is protected by firewall rules that restrict traffic on port 5432 strictly to the 100.64.0.0/10 private range.
  • The backend DATABASE_URL is set using the permanent overlay IP: postgresql+asyncpg://user:password@100.64.12.34:5432/tradeops.
  • When the ISP dynamic IP rotates, the Tailscale mesh routes the traffic seamlessly across the new path. No configuration updates are required on the backend.

5. Architectural Decision Record (ADR) Summary

For a list of design decisions, refer to the following records:

  • ADR-01: PostgreSQL as Primary Database: Neon PostgreSQL acts as the single source of truth for transactional data. Google Sheets is treated strictly as a write-only, non-blocking synchronization target.
  • ADR-02: Stateless JWT Authentication: Implemented via in-memory access tokens (lifetime 30 minutes) and HTTP-only, secure cookies for refresh tokens (lifetime 7 days).
  • ADR-03: Asynchronous Google Sheets Synchronization: To prevent slow network calls (200–800ms) to the Sheets API from blocking the main request-response cycle, updates are dispatched to background worker threads.
  • ADR-04: reportlab for PDF Generation: PDF rendering is executed in pure Python, removing headless browser execution (such as Puppeteer/Chromium) from the server runtime environment.
  • ADR-05: Server-Side Computed Payment Status: The payment status of invoices is derived dynamically using database constraints and server calculations, preventing data drift.
  • ADR-06: Cache-First GSTIN Lookup: External business registry API calls are mitigated via a local PostgreSQL cache with a 30-day expiration window.