Files
altium-render-engine/docs/ARCHITECTURE.md
T
nearology 56c5ee23d3
Verify / test (push) Failing after 2m54s
first commit
2026-11-05 17:31:17 +03:30

3.8 KiB

Architecture

flowchart LR
    C[External application] -->|authenticated multipart| A[FastAPI]
    A -->|generated private key| S[Local or S3 object storage]
    A -->|durable queued row| D[(PostgreSQL)]
    W[Independent worker replicas] -->|skip-locked lease| D
    W -->|bounded input| S
    W --> P[Resource-limited parser subprocess]
    P --> N[Native OLE / ASCII decoder]
    N --> G[Source records + versioned vector primitives]
    G --> V[SVG serializer]
    W -->|attempt-scoped JSON and SVG| S
    W -->|conditional completion| D
    B[Fullscreen browser] -->|read capability / expiry check| A
    A -->|JSON / vector artifact| B

The API persists the source before admitting a queued database row. Only committed rows are claimable. An advisory lock serializes PostgreSQL admission limits. A failure before a database commit may leave a private orphan file; it cannot be accessed through any API without a row. Production operators should audit/reconcile orphans and configure S3 lifecycle policies.

The queue is in PostgreSQL, using FOR UPDATE SKIP LOCKED and a conditional update on attempt/status. SQLite uses the conditional update for development. A lease lasts the parser timeout plus 60 seconds for process startup/artifact storage. A crashed claim is retried once. Every attempt writes to a different key prefix and updates completion only if its attempt is still current. The physical source is immutable.

API and worker can scale independently. Worker parsing is serial per worker container; increase replicas for concurrency. Parser subprocesses inherit no API key, database URL or storage credentials, receive files in an ephemeral directory, and run under CPU/address-space/file-size/FD limits. The decoder never fetches document URLs or loads dynamic code. This resource boundary is defense in depth; hostile-file deployments may additionally isolate parsers with a hardened runtime/network namespace.

Local object paths are application-generated and validated. Files are mode 0600 in directories created as 0700. Compose uses the same persistent volume and UID for API/worker. For multiple hosts replace local storage with an S3-compatible private bucket. Database metadata and objects must be backed up consistently. Credentials are environment settings, not committed files or source-derived values.

The normalized document keeps original property maps, owner relationships and active parts separately from drawables. This is necessary for diagnostics and future parser improvements: the SVG is an output, not the only stored interpretation. Source paint order is preserved. Geometry is not laid out by a graph library.

app/documents.py registers format adapters. To support PCB later, add a PCB adapter and PCB-specific data/layer types, reuse queue/storage/capability APIs, and provide layer-aware renderer/viewer behavior. The current endpoint intentionally accepts only SchDoc. Existing optional layer/net schema fields reserve extension points; no saved PCB data is fabricated, and no PCB functionality is implemented.

The viewer is dependency-free JavaScript with a pure tested camera module. It manipulates one SVG viewBox, schedules updates with requestAnimationFrame, and delegates vector rendering to the browser. There is no raster redraw loop or symbol substitution. Large native records are processed off the API process. Browser SVG performance at very large primitive counts has not been benchmarked; viewport culling or a hybrid renderer may be warranted after profiling, while preserving the same primitive model.

Initial schema creation is serialized on startup. This is schema version 1; database evolution must use explicit reviewed migrations. Healthz checks API/database availability; it does not prove a worker is making progress. Monitor queued age, active leases, failures, storage capacity and replica health in production.