DEV Community

AndersonBlake6857
AndersonBlake6857

Posted on

Property Users Open PDF Reports and Live Dashboard Links (Signature First)

TL;DR: For a monthly property report that must be signed and archived, publish a PDF as the record and include a live view as the investigation path. The least complex delivery is one notice with two clearly labeled links. Do not guess which one residents, owners, or managers will open. Measure each access path separately, while treating a hashed archive entry as the durable audit boundary.

Need Primary delivery Why it fits Signal to watch
Signed month-end record Archived PDF Fixed artifact can be hashed, signed, and retained archive success and signature verification
Current operating detail Live view Reader can inspect the latest underlying state authenticated view-open event
Review plus follow-up Both in one notice One records the period; one supports investigation opens by path, role, and month

The table is the decision. The rest is how to keep it honest in production.

Which link will users actually open?

There is no universal answer in the available evidence, and a year in the query does not turn preference into a fact. Property reporting has multiple audiences and jobs. An owner approving a monthly statement may need the archived record. A manager investigating an occupancy change may need current detail. The useful question is narrower: which path does each role open for this report, and does that path complete its intended job?

Instrument the choice. Record a PDF open only when archive access is authorized and served. Record a live-view open only after the authenticated report view loads. Keep delivery, open, signature, archive, and verification as different events; collapsing them into one report_viewed counter hides the exact failure an audit trail should expose.

A delivered notice proves neither artifact was read. A download does not prove a signature verified. A page load does not prove the month-end record was archived. Crisp names make crisp alerts.

Pick the archived PDF when the record is the product

Use the PDF path as primary when the job is to render the monthly report, bind it to a reporting period, obtain the required signature, and preserve the exact bytes that were accepted. PDF is standardized by ISO 32000-2. That makes it an appropriate document boundary, but the format alone is not an audit trail. The system still needs identity, time, artifact integrity, signature status, and retention metadata.

A practical archive record contains a property identifier, report month, immutable artifact identifier, content hash, signer identifier, signature state, and timestamps for rendering and archival. Keep the archived bytes aligned with that record. Consider a correction after the monthly report has already been signed: the source model changes, a new PDF is rendered, and the live view now reflects the correction. Replacing the old file at the same archive location would erase the connection between the signature and the bytes it covered. Create a new artifact identifier instead. Preserve the first artifact, link both versions, record why the second exists, and make the live view identify which archived version it currently reconciles to. This costs more metadata and requires the reader to see a version label. It also leaves an intelligible chain from the original acceptance to the corrected record. The signature-first axis makes that trade-off clear; convenience does not outrank traceability.

Freshness is the trade-off.

A fixed report can represent its stated period while no longer matching current operating state. Label the reporting period inside the document and beside its link.

Pick the live view when investigation is the job

Use the live path as primary when the reader needs to filter, inspect supporting rows, or see state that can change after month close. The view should still identify the property and reporting period. It should say when its data was refreshed, because a live presentation without time context invites the wrong comparison with an archived artifact.

A live link has a different security boundary. Authorization is evaluated at access time, and access can be logged against an authenticated principal. Make expiration and revocation explicit policy decisions. Avoid putting sensitive report data or durable credentials in the URL.

Picture the two paths. The investigation path runs from notice to authenticated view, then to supporting detail, then back to the archived month-end artifact. The record path runs from notice to authorized download, then to hash verification, then to the archive record. Two paths. One reporting job.

Implement one contract, then observe both paths

Generate the artifact and live view from one versioned report model. This reduces semantic drift without pretending the outputs are identical. The model below keeps audit fields near delivery fields and uses a discriminated event type so a metric cannot quietly confuse delivery with access.

import { createHash } from "node:crypto";

type DeliveryPath = "archived_pdf" | "live_view";

interface MonthlyPropertyReport {
  reportId: string;
  propertyId: string;
  month: `${number}-${number}`;
  modelVersion: number;
  renderedAt: string;
  archivedPdfUrl: string;
  liveViewUrl: string;
}

type ReportEvent =
  | { name: "notice_delivered"; reportId: string; role: string }
  | { name: "report_opened"; reportId: string; role: string; path: DeliveryPath }
  | { name: "signature_checked"; reportId: string; artifactId: string; valid: boolean }
  | { name: "archive_completed"; reportId: string; artifactId: string };

export function sha256(pdfBytes: Uint8Array): string {
  return createHash("sha256").update(pdfBytes).digest("hex");
}

export function recordOpen(
  emit: (event: ReportEvent) => void,
  reportId: string,
  role: string,
  path: DeliveryPath,
): void {
  emit({ name: "report_opened", reportId, role, path });
}
Enter fullscreen mode Exit fullscreen mode

The types prevent archive completion from masquerading as an open, and force every open to name its path. Application events can still be lost or duplicated. Give each production event a unique identifier, make ingestion idempotent, and reconcile the event stream against archive records.

Start with two ratios per role and report month: authorized opens divided by delivered notices for each path, and verified signatures divided by archived artifacts. Show counts beside ratios so a tiny audience does not look decisive. Do not call either ratio human attention; it measures system-observed actions. Privacy and retention rules should govern telemetry identifiers just as they govern the report.

Alert on broken obligations, not popularity. A rendered report without archive completion is actionable. A stored artifact whose hash differs on retrieval is urgent. A drop in one open path may deserve investigation, but it is not automatically an incident if the other path completes the job.

Test the contract at three layers. First, render the same fixture model into both outputs and assert that property, period, and totals agree. Second, mutate one byte in an archived fixture and require verification to fail. Third, confirm that a user who lost access cannot open the live view or fetch the PDF. After deployment, exercise rendering, archival, retrieval, and verification with a synthetic report that contains no customer data.

Limits and a practical decision rule

Open telemetry cannot reveal what a person understood, forwarded, printed, or discussed offline. Link scanners can create access traffic, so separate raw requests from authenticated view completion. Signature verification establishes a technical result under the implemented signing policy; legal effect depends on jurisdiction and process, which this field guide does not decide.

Make the archived PDF primary for acceptance, signature, and retention. Make the live view primary for current investigation. Deliver both when one monthly workflow needs both jobs. Measure them independently, and preserve the hash and audit metadata with the archived bytes.

That is enough.

Further reading

Top comments (0)