dp
dev.pipe Legal

Legal // PRIVACY

Privacy Policy

This page describes what the dev.pipe systems actually store. Every unmarked statement was read out of the source code of this service and can be checked against the files named beneath it. Blocks marked as a gap are legal or organisational statements that only the operator and their lawyer can make.

Service covered by this page: https://www.devpipe.eu

⚠ THIS PAGE IS INCOMPLETE AND MUST NOT GO LIVE

7 open gaps on this page

The blocks marked below are empty on purpose. They carry legal or commercial statements that only the operator and their lawyer can make. Every one of them is listed in docs/legal-content-checklist.md.

01Controller and data protection officer

⚠ MISSING — OPERATOR INPUT REQUIRED

Who is responsible for this processing

Required entries:

  • Name, legal form and address of the controller (Art. 4 no. 7 GDPR)
  • Contact address for data protection enquiries
  • Whether a data protection officer has to be appointed (section 38 BDSG) and, if so, their contact details
  • Representative under Art. 27 GDPR, if the controller is not established in the EU

Without these entries the whole policy has no addressee and no data subject can exercise a right.

02What the service does

You send a request from a development tool to an OpenAI-compatible endpoint. A gateway checks the API key and forwards the request to inference workers that hold the model in GPU memory. The control plane issues keys, counts usage and talks to Stripe for billing.

Verified in: config/litellm-config.yaml · docker-compose.yml · backend/app/api/v1/

03Data stored in the control-plane database

The control plane keeps the following rows in PostgreSQL. The list is complete for personal data as of the state of this code base.

TableStored fieldsNote
customers Email address, name, Stripe customer ID, active flag, created and updated timestamps Written when a subscription is paid for.
api_keys SHA-256 hash of the key, display prefix, key alias, key type, gateway key ID, rate limits, active flag, expiry, creation and revocation timestamps The key itself is never stored. For a trial claimed without a client identifier the alias is derived from the requesting IP address, so the alias itself is personal data.
subscriptions Stripe subscription ID, plan type, status, current billing period, timestamps Mirror of the state Stripe reports by webhook.
device_authorizations Email address in plain text, folded email identity, IP address in plain text, SHA-256 hash of a hardware fingerprint, SHA-256 digests of the device and user codes, attempt counters, timestamps Belongs to the device flow of the CLI installer. The IP address is stored in plain text, not hashed.
event_ledger Stripe event ID, event type, processing status, hash of the payload, processing timestamp Stops a Stripe webhook from being processed twice. No payload content is kept.
usage_metrics_hourly Counters only: requests, prompt, completion and cached tokens, latency buckets, throttled requests per hour and key No address, no IP address, no request content.

Verified in: backend/app/models/

04Short-lived data in Redis

Redis holds only counters and markers, each with an expiry. The longest lifetime in the code is seven days.

  • Abuse counters under hashed identifiers, so the identifier cannot be read back out of the counter
  • Spend markers for the proof-of-work challenge, so a solved challenge cannot be replayed
  • Usage aggregates that feed the cockpit charts

Verified in: backend/app/services/rate_limiter.py · backend/app/services/telemetry_pipeline.py

05The content of your requests

Prompts, source code and generated answers are held only in memory for as long as a request runs. Four independent settings keep them out of storage, and they are listed here so the claim can be verified rather than believed.

  • The gateway's only logging integration is our own usage forwarder, restricted to a fixed allowlist of token counters and key hashes; the gateway's own usage records likewise store no prompt or response text
  • The inference workers are started with --disable-log-requests, so prompts never reach their log
  • The reverse proxy strips the query string as well as request and response headers from its access log
  • The error tracker replaces prompt, message and token fields with a filter marker before an event leaves the process

Because no request content is written to disk anywhere in this stack, there is no data set here that could be used to train or fine-tune a model.

Verified in: config/litellm-config.yaml · config/litellm_usage_callback.py · docker-compose.yml · config/Caddyfile · backend/app/core/bugsink.py

06Web server access logs

The reverse proxy writes an access log to standard error. Query string, request headers and response headers are removed from every entry, which is what keeps API keys, session cookies and prompts out of it. The remaining fields still include the IP address of the requesting client.

⚠ MISSING — OPERATOR INPUT REQUIRED

Log retention

Required entries:

  • How long container logs are kept and where they are shipped
  • Whether log rotation is configured on the host; the compose files set no rotation limits
  • Retention period for the IP addresses in these logs

The stack itself never deletes a log line. What happens to it is decided outside this repository.

Verified in: config/Caddyfile

07Cookies and browser storage

This site sets exactly one cookie. It is called session_token, it is flagged HttpOnly and SameSite=Lax, it is sent with the Secure flag in production, and it expires after seven days. It exists so that a signed-in customer stays signed in. There is no analytics cookie, no advertising cookie and no tracking pixel, and the scripts use neither localStorage nor sessionStorage.

⚠ MISSING — OPERATOR INPUT REQUIRED

Consent assessment

Required entries:

  • Whether the login cookie is strictly necessary in the sense of section 25 (2) TDDDG and therefore needs no consent banner

The technical picture above is complete. The conclusion drawn from it is a legal one.

Verified in: backend/app/api/v1/auth.py · frontend/static/js/

08Fonts and other external resources

The web fonts are delivered from this server. Opening a page of this site therefore contacts no third-party server at all, and no IP address is disclosed to a font provider. A test keeps it that way for every public page.

Verified in: frontend/static/css/input.css · frontend/static/fonts/ · tests/test_frontend_assets.py

09Recipients and third parties

These are the only recipients that appear in the code. The legal basis column is deliberately empty.

RecipientWhat is transmittedWhenLegal basis
Stripe (payment processing) Email address, name, chosen plan, and the hash and prefix of a trial key that is being upgraded When a checkout session is created and whenever Stripe reports a subscription event — TO BE COMPLETED —
SMTP provider (not named in the code) Recipient address, subject and body of verification and sign-in emails Whenever such an email is sent — TO BE COMPLETED —
Bugsink error tracking (optional, self-hosted) Exception data with prompts, keys, tokens and cookies replaced by a filter marker; request path and status code Only when a server error occurs and only if the operator configured a DSN — TO BE COMPLETED —
Hugging Face (model weights) No customer data. The operator downloads model weights from there when a worker starts Never during a customer request Not applicable

⚠ MISSING — OPERATOR INPUT REQUIRED

Details only the operator knows

Required entries:

  • Which company actually sends the email, and where it processes the address
  • Which Stripe entity the contract is with and which transfer safeguards apply
  • Whether the error tracker is switched on in production and on whose infrastructure it runs
  • Hosting provider and data centre operator as a further processor
  • The legal basis for each row of the table above

Card details are entered on a Stripe page and never reach this system; everything else above depends on contracts the code cannot see.

Verified in: backend/app/services/stripe_service.py · backend/app/services/email_service.py · backend/app/core/bugsink.py · docker-compose.yml

10Automated checks on trial requests

A trial key is issued without a credit card, which is why the system decides automatically whether a request looks legitimate. It compares the IP address against published ranges of cloud providers, rejects disposable mail domains, requires a proof-of-work solution and a confirmed email address, and grants one trial per address within a waiting period. A request that fails these checks is refused without a human looking at it.

⚠ MISSING — OPERATOR INPUT REQUIRED

Assessment of the automated decision

Required entries:

  • Whether this refusal amounts to an automated decision under Art. 22 GDPR and what has to be disclosed about it
  • How a person can ask for the decision to be reviewed

The mechanics above are described completely. Whether they are lawful in this form is a legal judgement.

Verified in: backend/app/services/datacenter_feed_service.py · backend/app/services/rate_limiter.py · backend/app/services/onboarding_service.py

11Storage period and erasure

This has to be stated plainly, because it is the point where the system does not yet do what a privacy policy usually promises: the backend contains no automated deletion path. No code path removes a row from the database. A revoked API key is flagged as inactive and given a revocation timestamp; its row, including the alias that may contain an IP address, stays. Only the entries in Redis remove themselves, after at most seven days.

⚠ MISSING — OPERATOR INPUT REQUIRED

Retention periods and erasure process

Required entries:

  • Retention period for each table listed above
  • How a request under Art. 17 GDPR is carried out today, who does it and how it is documented
  • Which rows have to be kept for tax or commercial law and for how long
  • Whether an erasure routine will be built before launch

Do not write a retention period into this page that no code enforces. Either the routine gets built or the page says what really happens.

Verified in: backend/app/services/stripe_service.py · backend/app/api/v1/dashboard.py · backend/app/models/

12Purposes of the processing

The purposes are taken from the code. The legal basis for each of them is a legal assessment and is left open.

PurposeData usedLegal basis
Provide the inference service and manage API keys Key hash, prefix, alias, limits, customer reference — TO BE COMPLETED —
Issue trial access and keep it from being abused Email address, IP address, hardware fingerprint hash, counters — TO BE COMPLETED —
Billing, subscription management and invoices Email address, name, Stripe identifiers, plan, status — TO BE COMPLETED —
Send verification and sign-in emails Email address, one-time link or code digest — TO BE COMPLETED —
Operate the platform securely and find errors Access logs including IP address, scrubbed error events — TO BE COMPLETED —
Show usage figures in the cockpit Hourly counters per key, no content — TO BE COMPLETED —

13Your rights

Under the GDPR you may request access to your data (Art. 15), correction (Art. 16), erasure (Art. 17), restriction of processing (Art. 18) and a copy in a portable format (Art. 20), you may object to processing based on a legitimate interest (Art. 21), and you may lodge a complaint with a supervisory authority (Art. 77).

⚠ MISSING — OPERATOR INPUT REQUIRED

How to exercise these rights

Required entries:

  • Address or mailbox for such requests
  • Competent supervisory authority, which follows from the seat of the business
  • Internal process and response deadline
  • How an erasure request is satisfied while no deletion path exists

A list of rights without an address to send them to is of no use to anyone.