Privacy

What this platform holds about you

Last updated
August 11, 2026
Summary

This page describes a system rather than restating a template. Every statement below is a statement about code that runs today: which row is written to which table, what leaves the platform and where it goes, and what is removed and when. Where the honest answer is that something does not exist — a retention schedule, a deletion button, a signed agreement with a supplier — the page says so, instead of borrowing the sentence a privacy policy is normally expected to carry.

The standard this page is held to

The platform does not publish a figure it has not validated. The same rule governs this page: it does not describe a practice the software does not perform. A gap admitted is worth more than a reassurance that is false.

01Signing in

There is no password of yours, and four fields survive the handshake

Authentication is delegated to an identity provider you choose. The one exception is the break-glass credential sign-in on the console's own login screen, which exists for the case where the provider itself is what has failed: it checks one operator username and password held in the deployment's configuration, and it creates no client seat. No password of yours is held anywhere: no table carries such a column, and a check that runs on every build rejects any migration that would add one.

Three providers are built. A given deployment may hold credentials for all of them, some of them, or none — the sign-in dialog asks the deployment and reports what it finds rather than offering a button that cannot work. Whichever you use, the same four fields are read out of the response and the rest is discarded.

ProviderWhat is readVerified-address flag
GoogleSubject identifier, email address, display nameReported
LinkedInSubject identifier, email address, display nameReported
MicrosoftTenant and object identifiers combined into one identifier, email address, display nameReported
The rest of the response is dropped.

Every provider returns more than four fields. Google sends a profile picture, given and family names and a hosted domain; LinkedIn a locale and a picture; Microsoft a user principal name and group memberships. None of them is read, stored or forwarded. The code takes an identifier, an address, a display name and a verification flag, and lets the remainder of the response go out of scope.

Three rows are written, once.

An account row, holding a display name, the plan tier and the trial dates. A seat row, holding your email address, your display name, your role, a preferences object and the time you were last seen. An identity row, linking that provider and its identifier for you to that seat. Signing in again updates the last-seen stamp and the address your provider currently reports; it creates nothing new.

The account's name may be your own name.

When a genuinely new account is created, its name is taken from the display name your provider returned — or, when the provider returned none, from your email address. That is the one field on the account record that can carry a person's identity, and it is worth knowing it is there.

An unverified address is refused, and nothing is written.

When a provider states that the address it gave has not been verified, the sign-in stops there. The transaction that would have created your account is rolled back, no row survives it and no session is created. A provider that says nothing either way is not treated as a refusal — silence is not a denial, and the sign-in proceeds without that check.

Your role is decided here, never by the provider.

Operator access is granted from a list held in the deployment's own configuration and matched against your address. No claim inside a provider's token can grant it, and none is read for that purpose.

No long-lived credential for your provider is kept, and there is no unlink control.

The sign-in exchange returns tokens that would let this platform act at your provider afterwards. None is stored: what survives the handshake is the identifier, the address and the display name described above. Two consequences, and the second is the kind this page exists to state rather than omit. Signing out ends the session recorded here and needs nothing from your provider. But the console has no control that detaches a provider from your seat — the link is removed only when the account itself is deleted, which section 08 describes. Ending the platform's access at your end is done in your provider's own account settings, where the permission was granted.

02Using the console

What is written while you work

Everything a signed-in session creates is written to the platform's own database and to nowhere else. The list below is meant to be complete: if something is not named here, it is not stored.

Watchlists.

The list name, the symbols in it, any note you type against a symbol, up to eight short tags per symbol, and the columns you chose to display. The note is free text and the console never inspects it.

Saved screens, and when they ran.

The filter itself is three fields: a horizon, a signal class and a minimum confidence. Symbols, sectors and free text cannot be part of a screen, because those three are the only fields the specification accepts. Stored alongside it: when the screen last ran, the data date it ran against, how many names it returned, and whether you put it on a schedule.

Saved strategies, and their edit history.

The name, the template family and version, and your own parameter overrides. A database trigger writes a full snapshot of that definition every time it changes, so the version history is kept as well as the current state.

Strategy runs.

The request is stored as you sent it, under its own key, including a list of symbols when the client sends one. Beside it sits a frozen copy of the strategy as it stood when the run was queued, the run's status and timings, and what it was charged.

Alert rules, and every firing.

The rule: its name, what it watches — a symbol, a sector, a watchlist, a book or a saved screen — the condition, and the channel. Each time it fires, a delivery row is appended with the payload, and for a price, prediction or screen rule that payload names the securities that matched. The delivery log is append-only: once written, a row's contents cannot be edited.

A webhook endpoint, if you configure one.

The address you gave and a signing secret generated here, plus the outcome of the last attempt. HTTPS is required by the database itself, not only by the code that calls it.

The credit ledger, which is narrower than it sounds.

A ledger row records the account, one of five fixed action names, how many assets were involved as a count, the breadth, span and depth multipliers, the cost, and the balance afterwards. It names no security whatsoever, and it names no person: the row is attributed to the account, and although columns exist for a user and a request identifier, nothing writes them. The parameters absent from the ledger are present on the strategy run, which is linked to you — the two are separate records and must not be read as one.

Sessions.

One row per sign-in: a random session identifier, the seat, your email address as the token's subject, which provider you used, when it was issued and when it expires, when it was last active, and a deliberately coarse device fingerprint. What that fingerprint is not is the subject of the next section.

Three preferences.

Theme, whether the console's sidebar is collapsed, and the language of the public site. The route accepts exactly those three keys and rejects a fourth with an error rather than dropping it silently.

03What is not collected

The absences, named

A privacy policy is usually vague here. These are specific, and each is a property of the code rather than a statement of intent.

No password of yours, and nowhere to hold one.

Identity is delegated. The only credential this console checks is the operator break-glass login of section 01, whose username and password live in the deployment's configuration and in no table. There is no password column in any table and no hashing routine anywhere in the console; a check that runs on every build reads the migrations and fails if such a column appears.

No payment details.

No payment processor is connected to this console. No card number, bank detail or billing address is requested, entered, stored or forwarded, because there is nothing here to enter one into.

No full IP address, anywhere.

The session record holds a network prefix rather than an address: an IPv4 address is stored with its final part zeroed, an IPv6 address as its first three groups. The truncation happens before the value is written, and an address the parser cannot read is stored as nothing rather than as a guess. The public contact form does read a caller's address in order to rate-limit itself, but that value lives in the running process's memory for an hour and is written to no database, no log and no message.

No raw browser string.

The User-Agent header is parsed once into three coarse words — a browser, an operating system, a device class — and the header itself is discarded. Any of the three that is not recognised stays empty rather than being filled with a guess.

No location.

There is a column on the session record for the country a sign-in came from, and nothing writes it. No geo-location source exists anywhere in the platform, so that column is empty on every row and the platform cannot say where you are.

No research history — with two exceptions, which we name.

There is no table of what you looked up. The screener is a read-only query, the research routes are reads, and no route records which symbol was requested. The two exceptions are real and should not be glossed over: a SAVED screen keeps when it last ran and how many names it returned, and an alert keeps what it checked and which symbols matched. Ad-hoc research leaves nothing behind; saved objects do.

No administrative audit trail — and this cuts both ways.

Two tables exist to record operator actions — one of them shaped to hold a full IP address and a raw browser string — and nothing in the console writes a row to either. That is why the two absences above can be stated without qualification: no full address and no raw browser string is stored anywhere in the platform today. It is also a control this platform does not yet have, which is the less comfortable half of the same fact, and you should hear it here rather than work it out later.

No analytics inside the console.

The analytics tag and its consent banner are imported by the public site's layout and by nothing else. The reason is written into the code: a console URL names the security a signed-in client is researching, and that must not reach an analytics provider.

Nothing about you reaches the research warehouse.

The analytical database holds market, fundamental and macroeconomic data. No user row, no identifier and no record of anything a person did is ever written to it. When you run work through the platform's research services, the console signs the call with a fixed service identity — your identity, your address and your session do not cross that boundary.

04Cookies and local storage

Five cookies, five keys, and one question

Every cookie below is set by this site itself. None is an advertising cookie, and no third party sets a cookie here unless you accept analytics on the public pages.

CookieWhat it doesHow long
opulence_sessionYour signed-in session. Not readable by scripts on the page.12 hours
oa_oauth_state_…, oa_oauth_nonce_…, oa_oauth_pkce_…One sign-in handshake: they bind the round trip to your browser so it cannot be forged. They carry random values and nothing about you. Only the first is always set — the other two exist for providers whose handshake needs them, which today means Microsoft.10 minutes, deleted the moment the handshake completes
oa-viewAn operator's view-as-client toggle. Presentation only — it grants no access, and a client session gains nothing by setting it.Until the browser closes

The session cookie is a signed token rather than an opaque reference, and its payload contains your email address in a readable encoding. It is signed, not encrypted, so anyone holding the cookie can read the address out of it — which is the same person who could already use the cookie to be you. Nothing else is in it: no name, no role, no account details. The server checks the signature on every request and the session's live database record at most once every 20 seconds per running process, which is what makes revoking a session take effect within seconds rather than at expiry.

Local storage

Five keys, all of them preferences. Local storage is not a cookie and does not travel with a request, so nothing here is read off your browser by a request. The first three are the same three preferences section 02 describes, and pressing Save on the Profile screen writes them to your seat as well.

KeyWhat it holds
oa-themeLight or dark
oa-railWhether the console's sidebar is collapsed
oa-langEnglish or Turkish, for the public site
oa-consentYour answer to the analytics question, so it is not asked again
opulence.trial-banner-seenThat you dismissed the trial notice
The analytics question
It is only asked when there is something to ask about.

The public site runs Google Analytics 4 only when the deployment has been given a measurement id. Without one — and an unset, malformed or placeholder id all count as without one — there is no tag on the page and no banner asking about one. A banner requesting permission for something that is not happening is a request for consent to nothing.

Decline means the tag is never loaded.

This is stronger than the usual arrangement, in which the tag loads and is then asked to withhold storage. Here the script element is not put on the page at all, so your browser makes no request to Google: neither the page you are on nor the address you read it from ever reaches them. Nothing is queued beforehand either, so accepting later cannot ship the pages you already read.

Accept means the path, and only the path.

The page view carries the path, the origin and the page title. The query string is never sent, which matters because the query string is where a symbol would sit. Only analytics storage is ever granted; the three advertising signals are set to denied before anything loads and are never asked for, because this product runs no advertising.

One limit on that claim, stated rather than buried.

Analytics properties carry a setting called enhanced measurement, which makes Google's own script emit further events — scrolls, outbound clicks, downloads — from its own reading of the page address. That setting lives in the analytics account, not in this codebase, and nothing here can see or disable it. What this page can honestly claim is therefore what the page views this site sends carry, which is the path only.

Both answers are remembered, and both are equal.

Decline is the same size, the same weight and the same contrast as Accept, and the site behaves identically whichever you choose. Neither answer is asked again on your next visit.

05Third parties

Everyone else who sees anything

This list is meant to be exhaustive. If a name is not on it, it receives nothing.

The identity provider you sign in with.

Google, LinkedIn or Microsoft, according to your choice. Each learns that you signed in to this platform, and sees your own address and browser as a matter of making the request. Nothing about your research, watchlists or portfolios is ever sent to them, and the exchange that completes the sign-in runs on the server, so they do not observe what you do afterwards.

Google, as the mail carrier.

All platform email is sent through Google's SMTP service. That covers alert emails to your own address — which carry the rule's name, what it watches, and the payload, including the symbols that matched — messages sent through the public contact form, and reports an operator sends to a client. The connection is encrypted; Google, as the operator of that service, necessarily handles the messages in transit and in the mailboxes at both ends.

Google Analytics, on the public pages only.

Consent-gated exactly as section 04 describes, structurally absent from the signed-in console, and absent altogether when the deployment has set no measurement id.

Yahoo, for live market context.

This is the one that most needs saying. When you open a symbol in the console, the server asks Yahoo's public endpoints for that ticker's current quote, its recent headlines and, where available, analyst consensus and the next earnings date. The request is made by the server, so Yahoo sees the platform's own address and a fixed browser string rather than yours, and no cookie, session or account identifier travels with it — Yahoo cannot attribute the lookup to a person. What does cross is the ticker. A claim that nothing about your research ever leaves the platform would therefore be false, and this page does not make it.

Google, for scheduling — and only if you open the calendar.

The booking dialog embeds a Google appointment page. Closed, the frame does not exist and Google is not contacted at all. Opened, whatever you type into that calendar goes to Google rather than to this site, which cannot read inside it. Google's embed script is deliberately refused, so none of their code runs on this origin.

Any endpoint you configure yourself.

If you point an alert at a webhook, the alert payload goes to the address you gave — including the symbols that matched. It is signed so the receiver can verify it came from here, the destination must be HTTPS, addresses that resolve inside a private network are refused, and redirects are not followed. Your identity and your address are not in the body. What happens to it after that is between you and that endpoint.

Files you export yourself.

Three downloads leave with you: your data as JSON, the credit ledger as CSV, and a strategy document. The strategy document embeds the exporting user's email address in its provenance block, so sharing that file discloses your address to whoever receives it.

Nobody else.

No advertising network, no data broker, no customer-relationship tool, no session-replay recorder, no error-tracking service, no marketing pixel. The public pages load no third-party script other than the analytics tag described above, and the site's typeface is served from this origin rather than fetched from Google on each visit.

06Hosting and processing

Where it runs, and what the infrastructure records

The platform and its data are hosted on Google Cloud. That makes Google the infrastructure provider for everything on this page, in a role separate from the three named in section 05.

The console runs on Google Cloud Run, in a United States region.

Its databases run on Google Cloud as well, reached over a private network rather than the public internet. The research warehouse and the transactional database are not exposed to the internet at all.

Google's request log records the full URL. This application records almost nothing.

Every request to the console is logged by the hosting platform with the caller's address, the full URL including any query string, the browser string, the referrer, the response status and the latency. That log belongs to Google Cloud Logging and is written by the infrastructure, not by this application — which writes a single warning about a malformed analytics id and nothing at all in its data routes.

That must not be confused with the analytics claim.

Analytics is kept out of the console precisely so a URL naming a security cannot reach an analytics provider. The same URL still appears in the infrastructure request log for the request that served it. Both statements are true, and stating only the first would be misleading.

No retention period is stated for that log.

Nothing in this codebase configures logging, a retention setting or a log sink, so what applies is the hosting platform's own default. Naming a number here would be inventing one.

What can be said about encryption, and what cannot.

Webhook deliveries are refused unless the destination is HTTPS, enforced by the database as well as by the code. Outbound mail uses TLS. Beyond that: the connections between the console and its databases run inside a private network and nothing in this codebase configures transport encryption on them, and nothing here supports a claim about encryption at rest. So none is made.

07Retention

One rule exists. This is what the other tables do instead.

This is the section a policy is most tempted to fill with numbers. There is exactly one retention rule in the codebase, and it governs one table.

Sessions are removed 30 days after they expire.

A session row outlives the session itself so that “a new device signed in last Tuesday” stays visible after that session ends. Thirty days past expiry, it is deleted. Three qualifications, because each of them matters: the sweep is not a scheduled job — it runs when somebody opens the sessions list; it is budgeted to once an hour per running process; and a session you revoke is removed 30 days after it would have expired, not 30 days after you revoked it.

Everything else is kept indefinitely.

Watchlists, saved screens, saved strategies and their version history, strategy runs, alert rules, alert deliveries, alert evaluations, webhook configuration, account and seat records, identity links, and the credit ledger. No cleanup job, no scheduled task and no expiry applies to any of them. They remain until somebody removes them.

Three of those cannot be edited, and one of them cannot be deleted either.

The alert delivery log, the credit ledger and the strategy version history are append-only, enforced by the database rather than by convention. A delivery row can have its status advanced and nothing else. That is deliberate — a receipt you can rewrite is not a receipt — and its cost is that those three records cannot be selectively cleaned. Only the credit ledger is protected against deletion as well; the other two are removed with the alert rule or the saved strategy they hang off, which is what section 08 describes.

A trial ending is not a deletion.

The trial end date governs what your account may do. Nothing is removed when it passes and nothing about your data changes; the entitlement is simply recomputed on the next request.

No schedule is published that the system does not run.

When retention rules exist for the tables above, this section will say what they are. Until then it says this.

08Your copy, and deletion

One of these is a button. The other is a person.

Both routes are real and both are described exactly as they behave, including where the first one is incomplete and where the second one is manual.

A complete copy, on demand, from the Profile screen.

One link streams every row the console holds for you as a JSON file: your seat record, your linked identities, watchlists and their members, saved screens, saved strategies, strategy runs, alert rules, alert deliveries, and your account's credit ledger. It is built so new columns cannot silently fall out of it, and a section that fails to read says so inside the file rather than appearing as an empty list. There is no job to queue and nothing is emailed.

And what that copy does not yet include.

Six things are absent, and naming them is the point of this paragraph: your session records, including their device fingerprints and network prefixes; the version history of your saved strategies; the current evaluation state of each alert rule; your webhook configuration; the billing account record; and the account row itself, with its tier and trial dates. Portfolio books are excluded deliberately and the file says so. The rest is a gap in the export rather than a decision, and it is listed here so the download is not read as more complete than it is.

You can delete your own objects, immediately.

A watchlist, a symbol within one, a saved screen, a saved strategy, an alert rule and your webhook configuration are each removed by the console when you ask it to — permanently, at once, with nothing queued. The removal reaches what hangs off them: deleting a saved strategy takes its version history with it, and deleting an alert rule takes its delivery log.

Deleting the account itself is done by a person, on request.

There is no automated route for it today: no self-service button, no operator control and no script. Ask through the contact form and an operator removes the records by hand. Every table that hangs off your seat cascades from that deletion, so removing it removes the watchlists, screens, strategies, runs, alert rules, sessions and identity links attached to it. The console's Profile screen says exactly this and deliberately shows no delete button, because a control that appeared to delete an account and did not would be the worst thing on that screen.

One record does not go with it, and the database is why.

The credit ledger belongs to the account rather than to your seat, and it is protected against deletion as well as against editing — the database refuses to remove a ledger row at all, so an account-level deletion cannot take it out without that protection being lifted first. Section 07 explains why it is written that way. What survives is a list of how much work an account did and what it cost: no security is named in it and, as section 02 says, no person is either.

No timeframe is promised, on purpose.

A deletion run by hand has no queue anybody measures, and a deadline nobody can keep is worse than none. What is promised is that you are told when it is done. If a self-service control is built, this is the paragraph that will describe it.

One thing that is not done here.

Removing this platform's permission at your identity provider is done in that provider's own account settings, not from this console — see section 01. Deleting your account here removes what this platform holds; it does not reach into Google, LinkedIn or Microsoft to withdraw a consent you granted there.

09Questions

Ask a person

Anything on this page, or anything that is not on it: use the contact form and a person reads it. It is also the route for a copy of your data if the download does not cover what you need, and the route for deletion.

The mailbox address is deliberately not printed anywhere on this site — publishing an address on a public page is how it fills with automated mail — so the form delivers to it on the server. The message itself is not stored: it exists as the email it becomes and nowhere else. If a deployment cannot send mail, the form says so rather than accepting your message and losing it.

Scope

What this document is, and what it is not

This page describes what the software does. It makes no legal determination: it does not claim compliance with any privacy statute, does not state a lawful basis for anything, does not name a data-protection officer, does not describe a mechanism for transfers between jurisdictions, and does not claim a certification of any kind. There is no data-processing agreement with any party named in section 05. Where you might expect one of those statements, its absence is the accurate answer.

Formal terms are in preparation and will be published when they are ready. When they are, they and this page have to agree — and this page is the one that describes what the code actually does.

When the system changes, this page changes with it and the date at the top moves. It moves for nothing else.

Final step

Invest like an institution. Without becoming one.

Stop reacting to the market. Run an institutional research process on your own holdings: continuous analysis, forecasts with stated uncertainty, and a scorecard for every number the platform publishes.

See the architecture