Skip to content

Data Flow Diagrams β€” Gevell PDF


1. Data classification

IDClassExamplesSensitivityPrimary store
D1Customer documentsPDFs and Office files uploaded for conversionHigh β€” may contain FERPA-covered recordsCloudflare R2
D3Account & identity dataEmail, name, organization, auth identifiers, tenant/team membershipModerateSupabase PostgreSQL
D4Billing & usage dataEntitlements, usage records, invoice referencesModerateSupabase PostgreSQL
D5Derived analysisConformance results (PDF/UA, WCAG) and accessibility reportsModerate (derived from D1)Supabase + R2
D6Operational metadataJob status, page counts, cost records, structured logsLowSupabase, Amazon CloudWatch Logs

The platform holds no payment instrument β€” institutional accounts are billed by invoice against recorded usage.


2. Trust boundaries

#BoundaryCrossing controls
TB-1Public internet β†’ Cloudflare edgeTLS 1.2+, DDoS protection, and the Cloudflare Web Application Firewall (managed rule sets plus rate limiting) in front of the web applications and the primary API
TB-2Browser β†’ object storage (direct upload/download)Short-lived presigned URL, issued only after an authorization check, scoped to one object key and method
TB-3Edge β†’ API (AWS)TLS, origin authentication, request-scoped JWT or hashed API key. The serverless API (api-pdf.theaccessible.org) is reached directly at AWS API Gateway rather than through Cloudflare; it is protected by API Gateway request throttling and application-level rate limiting
TB-4API β†’ data storesLeast-privilege credentials; PostgreSQL row-level security; parameterized queries only
TB-5API β†’ processing tierThe processing host is one always-on AWS EC2 instance in us-east-1 (an Auto Scaling group of one across two Availability Zones) whose security group allows no inbound traffic; requests reach it only through an outbound-initiated Cloudflare Tunnel. It is administered only through AWS Systems Manager (no SSH, no key pair), requires IMDSv2, uses encrypted EBS disks, and loads its secrets from AWS SSM Parameter Store (KMS-encrypted SecureStrings) into memory at start
TB-6Queue β†’ processing tierMessages carry job IDs and object keys only β€” never document bytes
TB-7Platform β†’ AI inferenceTLS to AWS Bedrock in-region under Zero Data Retention; fails closed if a ZDR path is unavailable
TB-9Platform β†’ subprocessors (email provider, customer storage integrations)Scoped credentials; minimum necessary payload; disclosed in the subprocessor list
TB-10Operator β†’ productionMulti-factor authentication is required on every administrative account for our infrastructure and service providers (AWS, Cloudflare, Supabase, GitHub, Google Workspace), with a move to phishing-resistant passkeys completing by Sep 30, 2026; access-gated admin surfaces; no contractor or offshore access; the processing host is administered only through AWS Systems Manager; AWS CloudTrail records account activity and AWS GuardDuty threat detection alerts the CTO

3. Level 0 β€” Context diagram

flowchart LR
accTitle: Context diagram for Gevell PDF
accDescr: Customers submit documents and receive accessible outputs and conformance reports, while the platform exchanges data with inference, identity and email services.
U["Customer user<br/>(institution staff)"]
ADM["Gevell operator"]
SYS["Gevell PDF"]
AI["AWS Bedrock β€” Anthropic Claude<br/>(Zero Data Retention)"]
MAIL["Resend (transactional email)"]
IDP["Institutional IdP<br/>(SAML SSO / LTI)"]
U -->|"D1 documents Β· D3 account data"| SYS
SYS -->|"accessible outputs Β· D5 conformance reports"| U
SYS <-->|"D1 page images + text (inference only)"| AI
SYS -->|"D3 addresses, notification text"| MAIL
SYS <-->|"D3 assertions"| IDP
ADM -->|"operational queries (D6)"| SYS

Description: customer users submit documents and account data, and receive accessible outputs and conformance reports. The platform exchanges page images and extracted text with AWS Bedrock for inference only, sends notification email through Resend, and federates identity with institutional identity providers. Operators see operational metadata.


4. Level 1 β€” Shared decomposition

flowchart TB
accTitle: Level 1 decomposition of the shared platform
accDescr: The edge serves the application shell, the API authenticates callers and creates jobs, queues feed the processing hosts, and results are written back to object storage and the database.
U["Customer user"]
subgraph TB1["TB-1/TB-2 Β· Cloudflare edge (US)"]
P1["P1 Β· Serve application shell<br/>pdf.gevell.com"]
DS1[("DS1 Β· R2<br/>D1 documents Β· outputs")]
DS2[("DS2 Β· KV<br/>sessions, file metadata, share tokens")]
end
subgraph TB3["TB-3/TB-4 Β· Stateless API (AWS us-east-1)"]
P2["P2 Β· Authenticate & authorize"]
P3["P3 Β· Manage files & jobs"]
P4["P4 Β· Meter usage"]
DS3[("DS3 Β· PostgreSQL<br/>D3 Β· D4 Β· D5 Β· D6")]
Q[("DS4 Β· Job queues<br/>pointers only")]
end
subgraph TB5["TB-5/TB-6 Β· Processing tier (AWS EC2 us-east-1, no inbound access)"]
P5["P5 Β· Render, extract & analyze<br/>PDF toolchain"]
P6["P6 Β· Validate<br/>veraPDF Β· WCAG rule engine"]
end
AI["AWS Bedrock (ZDR)"]
IDP["Institutional IdP"]
U --> P1 --> P2
P2 <--> IDP
P2 --> DS3
P2 --> DS2
U -->|"D1 direct upload via presigned URL"| DS1
P3 -->|mint presigned URL| U
P3 --> DS3
P3 --> Q --> P5
P5 -->|read original| DS1
P5 -->|"D1 page images + text"| AI
AI -->|proposals| P5
P5 --> P6
P6 -->|"outputs"| DS1
P6 -->|"D5 conformance results"| DS3
P4 --> DS3
DS1 -->|"outputs via presigned URL"| U

Description: the edge serves the application shell. The API authenticates users, records files and jobs in PostgreSQL, mints short-lived presigned URLs so document bytes move directly between the browser and object storage, and places job pointers on a queue. The processing tier renders and extracts content from uploaded documents, obtains proposals from Bedrock, validates deterministically, then writes outputs to object storage and conformance results to the database. Usage is metered from job records and invoiced from those records.


5. Level 2 β€” Gevell PDF (document conversion)

sequenceDiagram
accTitle: Document conversion sequence
accDescr: The browser requests a presigned URL and uploads bytes directly to a scan-staging bucket; only on a clean malware verdict is the file admitted, converted on a processing host, and its outputs written back to storage.
autonumber
participant B as Browser
participant API as API
participant S3 as S3 scan staging
participant GD as GuardDuty Malware Protection
participant R2 as R2 object store
participant DB as PostgreSQL
participant Q as Pipeline queue
participant W as Processing host (EC2)
participant AI as Bedrock (ZDR)
participant V as veraPDF
B->>API: POST /api/files/upload (authenticated)
API->>DB: create file record (metadata only)
API-->>B: presigned PUT URL (single object, short TTL)
B->>S3: upload document bytes directly (TLS)
S3->>GD: scan on upload
GD-->>S3: verdict
Note over S3,R2: clean β†’ admitted to primary store<br/>infected or unscannable β†’ rejected (fail closed)<br/>staging objects lifecycle-expired after 1 day
S3->>R2: admit clean object
B->>API: POST /api/convert/{fileId}/estimate
API-->>B: page count + cost estimate
B->>API: POST /api/convert/{fileId}
API->>DB: check entitlement and credit balance
API->>Q: enqueue {jobId, objectKey}
Q->>W: deliver job pointer
W->>R2: GET original bytes
W->>AI: page images + extracted text
AI-->>W: reading order, structure, alt-text proposals
W->>V: validate candidate tagged PDF (PDF/UA-1)
V-->>W: conformance result
W->>R2: PUT accessible HTML + tagged PDF + report
W->>DB: job complete, page count, cost ledger entry
B->>API: GET /api/files/{fileId}/status β†’ complete
API-->>B: presigned GET URLs for outputs
B->>R2: download outputs (TLS)

Description: the browser requests a presigned upload URL and uploads bytes directly to a scan-staging bucket; the file is admitted to the primary store only after a clean malware verdict. Conversion is requested separately, priced, checked against entitlements, and enqueued as a pointer. A processing host reads the original, obtains structural proposals from Bedrock, validates the candidate tagged PDF against PDF/UA-1 with veraPDF, writes outputs back to object storage, and records completion and cost. Outputs are retrieved through short-lived presigned download URLs.

What crosses each boundary:

HopPayloadClass
Browser β†’ staging bucketFull document bytesD1
Staging β†’ primary storeFull document bytes (clean only)D1
API β†’ queueJob ID, object key, user IDD6
Processing host β†’ BedrockPage images, extracted text, system promptD1
Processing host β†’ PostgreSQLStatus, page count, cost, error textD6
Processing host β†’ object storeAccessible HTML, tagged PDF, reportD1 / D5
Logs & alerts (all hops)Request ID, user ID, duration, statusD6 β€” never document content

6. Authentication and session flow (both products)

flowchart TB
accTitle: Authentication and session flow
accDescr: Password, emailed link, one-time code and institutional identity provider paths all converge on an expiring JWT session scoped to a single user and tenant.
U["User"] --> C{"Sign-in method"}
C -->|password| A1["Auth provider verifies hash<br/>(plaintext never seen by Gevell)"]
C -->|magic link / email OTP| A2["One-time link or code via Resend"]
C -->|SAML SSO / LTI 1.3| A3["Institutional IdP assertion"]
A1 --> S["Session: 15-minute access token<br/>ends after 1 h idle, 12 h maximum"]
A2 --> S
A3 --> S
S --> RLS["Per-request tenant/user scoping at the API boundary<br/>+ PostgreSQL row-level security"]
RLS --> DATA[("Only rows and objects owned by that user/tenant")]
MK["Machine clients"] -->|"API key β€” SHA-256 hashed, expiry enforced"| RLS

Description: users authenticate by password, emailed link or one-time code, or an institutional identity provider; all paths converge on an expiring JWT session. Every request is scoped to the caller’s user and tenant at the API boundary and again by database row-level security. Machine clients use hashed, expiring API keys through the same authorization path. Access tokens last 15 minutes; a session ends after 1 hour of inactivity and expires 12 hours after sign-in regardless of activity. With SSO, the institution’s identity-provider policies also apply.


7. Usage metering and invoicing flow

flowchart LR
accTitle: Usage metering and invoicing flow
accDescr: Every billable operation writes a cost-ledger record and decrements the account allowance; institutional accounts are invoiced against recorded usage rather than charged to a stored payment instrument.
JOB["Completed conversion or parse"] --> LEDGER[("Cost ledger<br/>operation type, resource, cost, timestamp")]
JOB --> ENT["Entitlement / allowance decrement"]
ENT --> DB[("PostgreSQL")]
LEDGER --> DB
DB --> INV["Usage reports and invoices<br/>(billed to the institution on terms)"]
LEDGER --> MON["Spend monitors & kill-switches"]

Description: every billable operation writes a cost-ledger record and decrements the account’s entitlement or allowance. Institutional accounts are invoiced against those recorded usage figures on agreed terms; the platform itself holds no payment instrument and performs no payment processing. The cost ledger also drives spend monitoring and automatic kill-switches.


8. Deletion flow

flowchart TB
accTitle: Deletion flow
accDescr: Deleting a file removes the original, every derived output, and the associated metadata and share tokens; account deletion cascades the same way.
D1["Per-file delete"] --> R2X["Remove original and outputs from object storage"]
D1 --> KVX["Remove file metadata and share tokens"]
D2["Refund within refund window"] --> R2X
D3["Account deletion request"] --> SOFT["Soft delete β€” sign-in disabled,<br/>30-day grace window, restore link emailed"]
SOFT --> SWEEP["Scheduled hard-delete sweep"]
SWEEP --> R2X
SWEEP --> ANON["Anonymize account records"]
R2X --> BK["No separate document backup;<br/>database backups roll off after 7 days"]

Description: deleting a file removes the original, every derived output, and associated metadata and share tokens. Account deletion soft-deletes first β€” sign-in disabled, restore link issued, 30-day grace window β€” after which a scheduled sweep hard-deletes the account’s stored objects and anonymizes its records. Documents have no separate backup copy; database backups are retained for 7 days and then age out.


9. Retention summary

DataLocationRetention
Uploaded originals and derived outputsObject storeUntil the customer deletes the file or account β€” no time-based auto-expiry
Scan-staging copiesS3 staging bucket1 day (lifecycle)
File metadataKVLives with the file
Share-link tokensKVUntil link TTL expiry
SessionsKVEnds after 1 hour of inactivity; expires 12 hours after sign-in regardless of activity
Job metadataPostgreSQL13 months
Conformance results and reportsPostgreSQLWith the account (customer-deletable)
Request / usage logsPostgreSQL (90 days) Β· Amazon CloudWatch LogsRolling
AI prompt & response recordsPostgreSQL30 days
Billing and usage recordsPostgreSQL7 years (statutory)
Database backupsSupabase-managed, encryptedDaily; retained 7 days
Document backupsNone kept separatelyCloudflare R2 is replicated for durability and encrypted at rest

10. Flows that are explicitly not present

Stating the negatives is often what a reviewer actually needs:

  • No document or page content in queues, logs, alerts, or analytics. These carry identifiers and metadata only.
  • No model training on customer data. Inference runs under Zero Data Retention; where ZDR is unavailable the operation fails rather than falling back.
  • No human review of customer documents by Gevell staff in the normal course of processing.
  • No offshore processing or storage. All flows terminate in US regions.
  • No payment processing in the platform. Invoiced accounts are billed from recorded usage; the platform holds no payment instrument.
  • No inbound network path to the processing host. Its security group allows no inbound traffic; public traffic reaches it only through an outbound-initiated tunnel, and administration is only through AWS Systems Manager, with no SSH.
  • No customer data on company premises. All processing and storage run in cloud services in US regions.
  • No cross-tenant data path. Object keys are user-scoped and every read is mediated by an authorization check plus row-level security.