This commit is contained in:
+20
-2
@@ -7,9 +7,9 @@ Cross-origin browser access is allowed only from `https://git.sadentel.net`, wit
|
||||
Optional fields:
|
||||
|
||||
- `access`: `private` (default) or `unlisted`.
|
||||
- `expires_in`: positive integer seconds, maximum `LINK_TTL_SECONDS`. Expiry starts at upload acceptance, including queue time.
|
||||
- `expires_in`: `-1` for unlimited retention, or positive integer seconds up to `LINK_TTL_SECONDS`. Omit to use the configured finite default. `0` and values below `-1` are invalid. Finite expiry starts at upload acceptance, including queue time.
|
||||
|
||||
HTTP 202 includes `id`, `status`, `viewer_url`, `status_url`, `expires_at` (Unix seconds), `access`, and a `viewer_token` for private uploads. `Location` points to status and `Retry-After: 1` provides a polling interval. Do not automatically retry a POST after a transport failure: each accepted request creates a new resource. Idempotency keys are not implemented.
|
||||
HTTP 202 includes `id`, `status`, `viewer_url`, `status_url`, `expires_at` (Unix seconds, or `-1` for no expiry), `access`, and a `viewer_token` for private uploads. `Location` points to status and `Retry-After: 1` provides a polling interval. Do not automatically retry a POST after a transport failure: each accepted request creates a new resource. Idempotency keys are not implemented.
|
||||
|
||||
`GET .../{id}/status` returns HTTP 200 for existing, accessible, unexpired jobs, including failed jobs with `success: false` and a stable `error.code`. Failed artifacts return HTTP 422. Status does not disclose the original filename, source bytes or read token. The returned base `viewer_url` omits the original token: retain the initial URL or append your retained read token as a fragment.
|
||||
|
||||
@@ -49,3 +49,21 @@ A worker crash is retried after its lease expires, at most twice total. A parse
|
||||
## PCB preview and comparison
|
||||
|
||||
`POST /api/v1/pcbs/render` accepts `file`; `POST /api/v1/pcbs/comparisons` accepts `old_file` and `new_file`. Both require native `.PcbDoc` and reuse the existing asynchronous status, authentication, access and expiry conventions. They do not change schematic routes. See [PCB API and read/viewer endpoints](PCB.md).
|
||||
|
||||
## Unlimited links and embedding
|
||||
|
||||
All four creation operations (and the schematic comparison alias) accept `expires_in=-1`. The initial response and every status response return `expires_at: -1`. This sentinel is stored in the existing non-null timestamp column; no schema migration is required. Unlimited jobs remain claimable, count toward pending queue limits, retain private-token authorization, and are excluded from automatic expiry cleanup in both local and S3 storage. Other finite expiry behavior is unchanged. This is durable storage retention, not permanent RAM residency. External administrator deletion or provider lifecycle policies can still remove objects.
|
||||
|
||||
The upload results and authenticated/accessible viewers provide a **Share** button. It reveals a copyable iframe snippet using the complete viewer URL, including the read-token fragment for a private design. Sharing that snippet shares read access; it does not make the job `unlisted`, expose the service API key or bypass CSP. The viewer recovers its token from the resource-specific browser session if the fragment was already removed. Embedding remains restricted to the service itself and `https://git.sadentel.net`.
|
||||
|
||||
```html
|
||||
<iframe
|
||||
src="https://render.sadentel.net/view/pcb/PCB_ID#token=READ_TOKEN"
|
||||
width="100%"
|
||||
height="800"
|
||||
title="Altium design viewer"
|
||||
loading="lazy"
|
||||
referrerpolicy="no-referrer"
|
||||
allowfullscreen
|
||||
></iframe>
|
||||
```
|
||||
|
||||
+3
-1
@@ -27,7 +27,7 @@ curl -X POST https://render.sadentel.net/api/v1/pcbs/comparisons \
|
||||
-F 'access=private' -F 'expires_in=3600'
|
||||
```
|
||||
|
||||
Both creation requests return HTTP **202**, `Location: status_url` and `Retry-After: 1`. `access` defaults to `private`; `unlisted` is supported. Expiry is measured from admission, including queue time, and cannot exceed `LINK_TTL_SECONDS`.
|
||||
Both creation requests return HTTP **202**, `Location: status_url` and `Retry-After: 1`. `access` defaults to `private`; `unlisted` is supported. For finite links, expiry is measured from admission, including queue time, and cannot exceed `LINK_TTL_SECONDS`. Set `expires_in=-1` for unlimited retention (`expires_at: -1`); `0` and lower negative values are rejected.
|
||||
|
||||
Example render response (identifiers, timestamps and capabilities are illustrative):
|
||||
|
||||
@@ -161,3 +161,5 @@ Real HTTP smoke checks passed against an isolated loopback Uvicorn API with SQLi
|
||||
No connected browser was available, so actual pan/pinch/menu/iframe appearance remains unverified in a browser. No trusted Altium export was supplied, so geometric and font fidelity has not been certified against Altium output.
|
||||
|
||||
The final automated run includes native SchDoc and PCB fixtures, 154 passing Python tests and three passing frontend test files (camera, pointer interaction adapter and PCB layer policies). The standard Docker build was attempted with both normal and host networking, but dependency download stalled on `Temporary failure in name resolution` for PyPI's package host; those build attempts were stopped. A new Docker image was therefore not validated or deployed in this environment. The existing Dockerfile and dependency lock remain unchanged.
|
||||
|
||||
Both PCB viewers and upload results include Share → Copy iframe, preserving any private read capability in the URL fragment. Unlimited jobs are excluded from automatic cleanup; external S3 lifecycle policies must also permit retention. See [expiry and embedding](API.md#unlimited-links-and-embedding).
|
||||
|
||||
+1
-1
@@ -69,7 +69,7 @@ S3 replaces persistent **document object storage**, not the database. PostgreSQL
|
||||
|
||||
Multipart spooling and resource-limited parsing still use temporary local files, normally under `/tmp`, and remove them after processing. They are not durable artifact storage. In S3 mode no `STORAGE_DIR/objects` files are created/read as fallback. With PostgreSQL the adapter does not require a local storage directory. Existing Compose data volumes are retained for safe migration/rollback; they no longer receive document objects once S3 is selected. Do not delete a previous volume until its objects have been migrated and backups verified.
|
||||
|
||||
The bucket/prefix must be identical on all API and worker replicas. Bucket errors propagate through the existing storage error responses or durable failed-job status. An S3 outage does not switch new uploads to local storage. Object retention/lifecycle policies must not remove data earlier than the application link lifetime; database rows and S3 objects should be backed up together.
|
||||
The bucket/prefix must be identical on all API and worker replicas. Bucket errors propagate through the existing storage error responses or durable failed-job status. An S3 outage does not switch new uploads to local storage. Object retention/lifecycle policies must not remove data earlier than the application link lifetime; `expires_in=-1` jobs have no automatic expiry and need a provider policy that does not remove them; database rows and S3 objects should be backed up together.
|
||||
|
||||
Grant the service object permissions scoped to the chosen namespace: `s3:PutObject`, `s3:GetObject` and `s3:DeleteObject`. The application does not require public ACLs or bucket-wide listing for normal operations. Encryption/KMS may require additional provider permissions. Administrative backup and lifecycle tooling can have separate permissions.
|
||||
|
||||
|
||||
@@ -87,3 +87,5 @@ Tests cover record reordering, component UID matching/renumbering, values, pure
|
||||
The actual local `Sheet1-before.SchDoc` / `Sheet1-after.SchDoc` pair (205/206 source records) produced 1 moved component, 2 modified wires and 1 added junction. The 1,942-record CPU sheet compared with itself produced zero changes. These are structural integration checks, not a trusted Altium visual comparison or browser UI acceptance test. No proprietary samples are redistributed. Browser interaction and visual validation require a connected browser; absence of browser QA must be reported rather than replaced by camera unit tests.
|
||||
|
||||
Implementation verification: 115 Python tests and 6 frontend tests passed with the native fixtures enabled. The Docker image built successfully, the Caddy configuration adapted successfully, and real HTTP comparison plus single-file smoke checks passed against PostgreSQL with two worker replicas. The comparison result and SVG routes enforced private read tokens. A connected browser was unavailable, so interactive workspace appearance and browser behavior are not claimed as verified.
|
||||
|
||||
Comparison uploads also accept `expires_in=-1` for unlimited storage and link validity, with `expires_at: -1` in responses. The workspace menu and upload result include Share for a token-preserving iframe snippet; existing access and framing restrictions remain enforced.
|
||||
|
||||
مرجع در شماره جدید
مسدود کردن کاربر