ad2app-lib 1.22.0 → 1.23.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.graphifyignore +16 -0
- package/dist/legal/index.d.ts +15 -0
- package/dist/legal/index.js +32 -5
- package/dist/legal/locales.d.ts +31 -0
- package/dist/legal/locales.js +31 -0
- package/dist/legal/meta.d.ts +1 -1
- package/dist/legal/meta.js +1 -1
- package/dist/legal/privacy.js +20 -20
- package/dist/legal/privacy.pl.d.ts +14 -0
- package/dist/legal/privacy.pl.js +274 -0
- package/dist/legal/terms.js +51 -14
- package/dist/legal/terms.pl.d.ts +17 -0
- package/dist/legal/terms.pl.js +304 -0
- package/package.json +1 -1
- package/src/legal/index.ts +28 -0
- package/src/legal/legal-parity.test.ts +131 -0
- package/src/legal/locales.ts +47 -0
- package/src/legal/meta.ts +1 -1
- package/src/legal/privacy.pl.ts +273 -0
- package/src/legal/privacy.ts +20 -20
- package/src/legal/terms.pl.ts +303 -0
- package/src/legal/terms.ts +52 -14
package/.graphifyignore
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# Story worktrees are checkouts of OTHER branches living inside this repo. Without
|
|
2
|
+
# this, every symbol exists once per worktree and the graph answers structure
|
|
3
|
+
# questions with whichever stale copy it reaches first.
|
|
4
|
+
#
|
|
5
|
+
# This is not hypothetical: on 2026-07-29 ad2app-frontend had no such file, 8
|
|
6
|
+
# worktrees, and 26,693 of 30,385 graph nodes (88%) were stale copies —
|
|
7
|
+
# `graphify explain "Section()"` returned the wrong component from the wrong branch.
|
|
8
|
+
# This repo has no worktrees today, so it is clean by luck, not by configuration.
|
|
9
|
+
# Added preventively so the first worktree here cannot silently poison the graph.
|
|
10
|
+
.wt-*/
|
|
11
|
+
|
|
12
|
+
# Build + dependency output — never source of truth for structure questions.
|
|
13
|
+
node_modules/
|
|
14
|
+
build/
|
|
15
|
+
dist/
|
|
16
|
+
coverage/
|
package/dist/legal/index.d.ts
CHANGED
|
@@ -1,5 +1,20 @@
|
|
|
1
|
+
import type { LegalSectionsByLocale } from './locales';
|
|
1
2
|
export { LEGAL_META } from './meta';
|
|
2
3
|
export type { LegalMeta } from './meta';
|
|
3
4
|
export type { Block, InlineText, LegalSection, ListItem } from './types';
|
|
4
5
|
export { PRIVACY_SECTIONS } from './privacy';
|
|
6
|
+
export { PRIVACY_SECTIONS_PL } from './privacy.pl';
|
|
5
7
|
export { TERMS_SECTIONS } from './terms';
|
|
8
|
+
export { TERMS_SECTIONS_PL } from './terms.pl';
|
|
9
|
+
export { LEGAL_LAST_UPDATED, sectionsFor } from './locales';
|
|
10
|
+
export type { LegalLocale, LegalSectionsByLocale } from './locales';
|
|
11
|
+
/**
|
|
12
|
+
* The documents, keyed by locale, for callers that resolve at runtime.
|
|
13
|
+
*
|
|
14
|
+
* These live here rather than beside their English halves so that `terms.ts`
|
|
15
|
+
* and `privacy.ts` never import their own translations: a document should not
|
|
16
|
+
* have to know it has been translated. Consumers pass one of these maps to
|
|
17
|
+
* `sectionsFor(map, locale)`.
|
|
18
|
+
*/
|
|
19
|
+
export declare const TERMS_BY_LOCALE: LegalSectionsByLocale;
|
|
20
|
+
export declare const PRIVACY_BY_LOCALE: LegalSectionsByLocale;
|
package/dist/legal/index.js
CHANGED
|
@@ -1,9 +1,36 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.TERMS_SECTIONS = exports.PRIVACY_SECTIONS = exports.LEGAL_META = void 0;
|
|
3
|
+
exports.PRIVACY_BY_LOCALE = exports.TERMS_BY_LOCALE = exports.sectionsFor = exports.LEGAL_LAST_UPDATED = exports.TERMS_SECTIONS_PL = exports.TERMS_SECTIONS = exports.PRIVACY_SECTIONS_PL = exports.PRIVACY_SECTIONS = exports.LEGAL_META = void 0;
|
|
4
|
+
const privacy_1 = require("./privacy");
|
|
5
|
+
const privacy_pl_1 = require("./privacy.pl");
|
|
6
|
+
const terms_1 = require("./terms");
|
|
7
|
+
const terms_pl_1 = require("./terms.pl");
|
|
4
8
|
var meta_1 = require("./meta");
|
|
5
9
|
Object.defineProperty(exports, "LEGAL_META", { enumerable: true, get: function () { return meta_1.LEGAL_META; } });
|
|
6
|
-
var
|
|
7
|
-
Object.defineProperty(exports, "PRIVACY_SECTIONS", { enumerable: true, get: function () { return
|
|
8
|
-
var
|
|
9
|
-
Object.defineProperty(exports, "
|
|
10
|
+
var privacy_2 = require("./privacy");
|
|
11
|
+
Object.defineProperty(exports, "PRIVACY_SECTIONS", { enumerable: true, get: function () { return privacy_2.PRIVACY_SECTIONS; } });
|
|
12
|
+
var privacy_pl_2 = require("./privacy.pl");
|
|
13
|
+
Object.defineProperty(exports, "PRIVACY_SECTIONS_PL", { enumerable: true, get: function () { return privacy_pl_2.PRIVACY_SECTIONS_PL; } });
|
|
14
|
+
var terms_2 = require("./terms");
|
|
15
|
+
Object.defineProperty(exports, "TERMS_SECTIONS", { enumerable: true, get: function () { return terms_2.TERMS_SECTIONS; } });
|
|
16
|
+
var terms_pl_2 = require("./terms.pl");
|
|
17
|
+
Object.defineProperty(exports, "TERMS_SECTIONS_PL", { enumerable: true, get: function () { return terms_pl_2.TERMS_SECTIONS_PL; } });
|
|
18
|
+
var locales_1 = require("./locales");
|
|
19
|
+
Object.defineProperty(exports, "LEGAL_LAST_UPDATED", { enumerable: true, get: function () { return locales_1.LEGAL_LAST_UPDATED; } });
|
|
20
|
+
Object.defineProperty(exports, "sectionsFor", { enumerable: true, get: function () { return locales_1.sectionsFor; } });
|
|
21
|
+
/**
|
|
22
|
+
* The documents, keyed by locale, for callers that resolve at runtime.
|
|
23
|
+
*
|
|
24
|
+
* These live here rather than beside their English halves so that `terms.ts`
|
|
25
|
+
* and `privacy.ts` never import their own translations: a document should not
|
|
26
|
+
* have to know it has been translated. Consumers pass one of these maps to
|
|
27
|
+
* `sectionsFor(map, locale)`.
|
|
28
|
+
*/
|
|
29
|
+
exports.TERMS_BY_LOCALE = {
|
|
30
|
+
en: terms_1.TERMS_SECTIONS,
|
|
31
|
+
pl: terms_pl_1.TERMS_SECTIONS_PL,
|
|
32
|
+
};
|
|
33
|
+
exports.PRIVACY_BY_LOCALE = {
|
|
34
|
+
en: privacy_1.PRIVACY_SECTIONS,
|
|
35
|
+
pl: privacy_pl_1.PRIVACY_SECTIONS_PL,
|
|
36
|
+
};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { LegalSection } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* The languages the legal documents exist in.
|
|
4
|
+
*
|
|
5
|
+
* Polish is not optional politeness: Ad2app sp. z o.o. is a Polish provider
|
|
6
|
+
* selling to consumers, and for a Poland-resident consumer the terms have to
|
|
7
|
+
* be available in Polish. Until 2026-08-04 only English existed, so every
|
|
8
|
+
* Polish user was agreeing to a document in a language the law does not let us
|
|
9
|
+
* rely on against them.
|
|
10
|
+
*/
|
|
11
|
+
export type LegalLocale = 'en' | 'pl';
|
|
12
|
+
/** Per-locale sections for one document. */
|
|
13
|
+
export type LegalSectionsByLocale = Record<LegalLocale, LegalSection[]>;
|
|
14
|
+
/**
|
|
15
|
+
* Resolve a document for a locale, falling back to English.
|
|
16
|
+
*
|
|
17
|
+
* The fallback exists so a partially-translated document can never render as a
|
|
18
|
+
* blank page. It is NOT a licence to ship a half-translated policy: the
|
|
19
|
+
* document-level parity test asserts both locales carry the same section ids,
|
|
20
|
+
* so a missing translation fails the build rather than silently serving
|
|
21
|
+
* English under a Polish URL.
|
|
22
|
+
*/
|
|
23
|
+
export declare function sectionsFor(byLocale: LegalSectionsByLocale, locale: LegalLocale): LegalSection[];
|
|
24
|
+
/**
|
|
25
|
+
* The "last updated" line, per locale.
|
|
26
|
+
*
|
|
27
|
+
* A single hardcoded English date string ("6 July 2026") inside a Polish
|
|
28
|
+
* document is the kind of detail that makes a translated policy look
|
|
29
|
+
* machine-made, and dates are one of the things a reviewer checks first.
|
|
30
|
+
*/
|
|
31
|
+
export declare const LEGAL_LAST_UPDATED: Record<LegalLocale, string>;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.LEGAL_LAST_UPDATED = void 0;
|
|
4
|
+
exports.sectionsFor = sectionsFor;
|
|
5
|
+
const meta_1 = require("./meta");
|
|
6
|
+
/**
|
|
7
|
+
* Resolve a document for a locale, falling back to English.
|
|
8
|
+
*
|
|
9
|
+
* The fallback exists so a partially-translated document can never render as a
|
|
10
|
+
* blank page. It is NOT a licence to ship a half-translated policy: the
|
|
11
|
+
* document-level parity test asserts both locales carry the same section ids,
|
|
12
|
+
* so a missing translation fails the build rather than silently serving
|
|
13
|
+
* English under a Polish URL.
|
|
14
|
+
*/
|
|
15
|
+
function sectionsFor(byLocale, locale) {
|
|
16
|
+
return byLocale[locale] ?? byLocale.en;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* The "last updated" line, per locale.
|
|
20
|
+
*
|
|
21
|
+
* A single hardcoded English date string ("6 July 2026") inside a Polish
|
|
22
|
+
* document is the kind of detail that makes a translated policy look
|
|
23
|
+
* machine-made, and dates are one of the things a reviewer checks first.
|
|
24
|
+
*/
|
|
25
|
+
exports.LEGAL_LAST_UPDATED = {
|
|
26
|
+
// Derived, not copied. The first version of this file duplicated the English
|
|
27
|
+
// date here and left meta.ts untouched, so the same fact had two homes and
|
|
28
|
+
// nothing stopped them disagreeing. Only the Polish rendering is new.
|
|
29
|
+
en: meta_1.LEGAL_META.lastUpdated,
|
|
30
|
+
pl: '5 sierpnia 2026',
|
|
31
|
+
};
|
package/dist/legal/meta.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export declare const LEGAL_META: {
|
|
2
|
-
readonly lastUpdated: "
|
|
2
|
+
readonly lastUpdated: "5 August 2026";
|
|
3
3
|
readonly contactEmail: "kontakt@ad2.app";
|
|
4
4
|
readonly controllerName: "Ad2app sp. z o.o.";
|
|
5
5
|
readonly controllerAddress: "ul. Juliana Smulikowskiego 4A/21, 00-389 Warszawa, Poland";
|
package/dist/legal/meta.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.LEGAL_META = void 0;
|
|
4
4
|
exports.LEGAL_META = {
|
|
5
|
-
lastUpdated: '
|
|
5
|
+
lastUpdated: '5 August 2026',
|
|
6
6
|
contactEmail: 'kontakt@ad2.app',
|
|
7
7
|
controllerName: 'Ad2app sp. z o.o.',
|
|
8
8
|
controllerAddress: 'ul. Juliana Smulikowskiego 4A/21, 00-389 Warszawa, Poland',
|
package/dist/legal/privacy.js
CHANGED
|
@@ -33,7 +33,7 @@ exports.PRIVACY_SECTIONS = [
|
|
|
33
33
|
{
|
|
34
34
|
text: '**Social platform data via OAuth:** when you authorise a connection to one of the social media platforms you choose to connect (currently Instagram, TikTok, X (Twitter), YouTube, LinkedIn, Facebook, Threads, Pinterest, Reddit, and Bluesky), we receive data from that platform\'s API as permitted by your OAuth consent. Across all connected platforms this generally includes your account/profile data (such as user ID, username or handle, display name, avatar, and account statistics where the platform exposes them), the content and media of posts you compose, schedule, or publish through the Service, and performance/analytics data for your published posts. The specific data received depends on the platform and the permissions you grant. For some platforms we describe the data in more detail below:',
|
|
35
35
|
sub: [
|
|
36
|
-
{ text: '**TikTok:** basic profile (user ID, display name, avatar, biography, profile URL), account statistics (follower count, following count, like count, video count), video list and metadata (titles, view counts, engagement metrics), and
|
|
36
|
+
{ text: '**TikTok:** basic profile (user ID, display name, avatar, biography, profile URL), account statistics (follower count, following count, like count, video count), video list and metadata (titles, view counts, engagement metrics), and, where enabled for scheduling features, video upload and publish permissions. We request only the permissions required for the features you actively use.' },
|
|
37
37
|
{ text: '**Instagram:** Instagram Business account data including username, biography, profile picture, account type, and associated business metrics.' },
|
|
38
38
|
{ text: '**Facebook:** public profile information and, where you grant permission, your Facebook email address. Facebook is an independent OAuth provider separate from Instagram.' },
|
|
39
39
|
{ text: '**YouTube:** YouTube channel data (read-only: videos, statistics, channel metadata) and your Google Account profile (name, profile picture URL, Google Account ID) via the Google identity scope used for authentication.' },
|
|
@@ -41,15 +41,15 @@ exports.PRIVACY_SECTIONS = [
|
|
|
41
41
|
],
|
|
42
42
|
},
|
|
43
43
|
{ text: '**OAuth tokens and account connections:** publishing to your connected platforms is handled by our processor Zernio (see Section 6). For the platforms Zernio publishes to, we do not store your OAuth tokens ourselves; the tokens are held by Zernio on our behalf, and we hold only a reference to your connected account (platform name and username). For a small number of platforms where we read analytics directly (TikTok, Instagram, YouTube, Facebook), we may hold an access token ourselves. We are completing a technical review to confirm and, where needed, encrypt at rest every token we hold directly (see Section 10).' },
|
|
44
|
-
{ text: '**Audience data (aggregate only):** demographic and engagement statistics about your social media audience, as provided by the connected platform\'s API. This data is processed exclusively in aggregate statistical form and is not linked to any identified individual within your audience. We have assessed whether this data could constitute special category data under Art. 9 GDPR and confirm that we do not process such special category data
|
|
44
|
+
{ text: '**Audience data (aggregate only):** demographic and engagement statistics about your social media audience, as provided by the connected platform\'s API. This data is processed exclusively in aggregate statistical form and is not linked to any identified individual within your audience. We have assessed whether this data could constitute special category data under Art. 9 GDPR and confirm that we do not process such special category data: audience data is processed solely as aggregate numeric metrics.' },
|
|
45
45
|
{ text: '**Inbox data:** when you use the platform\'s inbox features, direct message conversations and post comments from your connected social media accounts are fetched and displayed. This includes content sent to you by your followers or other third parties on those platforms. See Section 11 for further detail.' },
|
|
46
46
|
{ text: '**Post content and scheduled posts:** the content you compose, schedule, and publish through the Service, including post text, captions, hashtags, links, scheduling times, and the images, videos, and other media you upload for those posts, together with the publishing status and metadata of each post. Where we cache a thumbnail or media preview for display in the app, we store only a pointer (a URL) to the file hosted by Zernio; we do not copy the underlying media into our own storage.' },
|
|
47
47
|
{ text: '**Published-post analytics:** performance and engagement metrics for posts you have published through the Service to your connected accounts (e.g. views, impressions, likes, comments, shares, reach, and other statistics), as provided by the connected platform\'s API.' },
|
|
48
48
|
{ text: '**Media and content:** files you upload (images, videos, documents) for posts or your profile.' },
|
|
49
|
-
{ text: '**Technical & usage data:** anonymised IP address, browser type and version, operating system, pages visited, referral URLs, timestamps, error and crash reports, and usage events (e.g. feature interactions such as button clicks and page views, tracked via PostHog
|
|
49
|
+
{ text: '**Technical & usage data:** anonymised IP address, browser type and version, operating system, pages visited, referral URLs, timestamps, error and crash reports, and usage events (e.g. feature interactions such as button clicks and page views, tracked via PostHog, see Sections 6 and 9). Usage tracking starts only after you give consent via the cookie banner.' },
|
|
50
50
|
{ text: '**Session replay data:** with your consent (see Section 9), we record replays of your interactions with the Service (mouse movement, scrolling, clicks, page navigation) to diagnose usability problems and errors. Values you type into form fields are masked before recording. We are extending this masking to also cover other user-authored text shown on screen during a recording (for example post captions or inbox messages displayed as read-only text); until that work is complete, such text may appear in a recording in readable form. Recordings are automatically deleted after 30 days.' },
|
|
51
51
|
{ text: '**Billing data:** Stripe, our payment processor, collects and holds your billing address and payment details when you subscribe. We ourselves store only a reference to your Stripe customer and subscription records (not your card details or billing address).' },
|
|
52
|
-
{ text: '**Marketing email preference:** whether you have opted in to marketing and lifecycle emails, and when (see Section 4). This preference is opt-in only
|
|
52
|
+
{ text: '**Marketing email preference:** whether you have opted in to marketing and lifecycle emails, and when (see Section 4). This preference is opt-in only, it is never pre-selected on your behalf, and you can withdraw it at any time via the unsubscribe link in any such email or by contacting us at {EMAIL}.' },
|
|
53
53
|
{ text: '**Feedback data:** free-text feedback submitted via the in-app feedback form. This may incidentally contain personal data you choose to include.' },
|
|
54
54
|
],
|
|
55
55
|
},
|
|
@@ -115,21 +115,21 @@ exports.PRIVACY_SECTIONS = [
|
|
|
115
115
|
kind: 'ul',
|
|
116
116
|
items: [
|
|
117
117
|
{
|
|
118
|
-
text: '**Service providers (data processors)
|
|
118
|
+
text: '**Service providers (data processors)**, engaged under contractual terms that include data protection obligations. A signed Data Processing Agreement (Art. 28 GDPR) is in place with our publishing sub-processor (Zernio); we are finalising written terms for the remaining sub-processors where not yet bound by their standard online DPA:',
|
|
119
119
|
sub: [
|
|
120
120
|
{ text: '**Zernio** (contracting entity: ARBICHAT, S.L., trading as \u201cZernio\u201d, zernio.com), social media API aggregation and publishing: we pass OAuth tokens, post content, media files, and inbox data to Zernio solely to execute publishing and inbox operations on your behalf. The vendor is based in Girona, Spain (EEA); see Zernio\'s own privacy policy for details of the infrastructure it uses. We have a signed Data Processing Agreement with this vendor; to the extent Zernio processes data outside the EEA, such transfers are covered by Standard Contractual Clauses (Commission Decision 2021/914) under that agreement.' },
|
|
121
121
|
{ text: '**Stripe**, payment processing: billing address and payment details are collected and held directly by Stripe; we share your email and account identifiers with Stripe to set up and manage your subscription. For processing your subscription payments on our behalf, Stripe acts as our data processor; for fraud prevention, anti-money-laundering checks, and its own regulatory compliance, Stripe acts as an independent data controller under its own privacy policy. Stripe is located in the United States and operates under the EU-US Data Privacy Framework.' },
|
|
122
122
|
{ text: '**PostHog (PostHog, Inc.)**, product analytics, session replay, and error tracking: usage event data (feature interactions, page views, device/browser info), masked session recordings, and error reports are processed only after you have given explicit analytics consent via the cookie banner. Some data we send is identifying rather than pseudonymised in specific cases (for example, transactional email delivery tracking uses your email address directly so we can tell whether an email reached you); we are reviewing which flows can be pseudonymised further. Our PostHog instance is **PostHog Cloud EU, hosted in Frankfurt, Germany**, analytics data is stored and processed within the EEA. PostHog, Inc. is incorporated in the United States; any residual access from outside the EEA is governed by a Data Processing Agreement incorporating Standard Contractual Clauses (Commission Decision 2021/914).' },
|
|
123
123
|
{ text: '**Resend**, transactional and product email delivery: we use Resend to send account verification emails, onboarding and lifecycle emails, and to maintain the list of users eligible for those emails. Resend receives your email address, and where relevant your first name and the content of the email (which may include a verification or unsubscribe link). Under Resend\'s data processing terms, personal data held by Resend is deleted within 90 days after termination of our agreement with them. Resend is a company based in the United States; transfers are covered by Standard Contractual Clauses (Commission Decision 2021/914) or the EU-US Data Privacy Framework where applicable.' },
|
|
124
|
-
{ text: '**Vercel Inc
|
|
124
|
+
{ text: '**Vercel Inc.**: backend API hosting and compute: server-side application code, API requests, and associated request logs are processed on Vercel\'s infrastructure. Vercel is located in the United States and transfers are covered by Standard Contractual Clauses (Commission Decision 2021/914).' },
|
|
125
125
|
{ text: '**Neon, LLC (an affiliate of Databricks, Inc.)**, PostgreSQL database hosting: all structured platform data (accounts, connected-account metadata, post content and scheduling metadata) is stored in a Neon-hosted PostgreSQL database operated under the Databricks Master Cloud Services Agreement and the Databricks Privacy Notice. Neon, LLC and Databricks, Inc. are companies incorporated in the United States; whether the database contents leave the EEA depends on the hosting region of our database instance, which we are confirming. To the extent data is processed outside the EEA, transfers are covered by Standard Contractual Clauses (Commission Decision 2021/914).' },
|
|
126
|
-
{ text: '**Google Firebase (Firebase Authentication)
|
|
126
|
+
{ text: '**Google Firebase (Firebase Authentication)**: authentication token verification: authentication tokens issued to users may be verified against Firebase Authentication to validate active sessions. Firebase is a Google service located in the United States and operates under the EU–US Data Privacy Framework.' },
|
|
127
127
|
{ text: 'A current list of sub-processors (including names, countries of processing, and applicable transfer safeguards) is available on request at kontakt@ad2.app.' },
|
|
128
128
|
],
|
|
129
129
|
},
|
|
130
130
|
{ text: '**Third-party tools you authorize:** see Section 6a. These tools are recipients acting on your instruction, not our sub-processors.' },
|
|
131
131
|
{ text: '**Legal authorities:** where required by law, court order, or to protect the rights and safety of ad2app or third parties.' },
|
|
132
|
-
{ text: '**Business transfers:** in the event of a merger, acquisition, or sale of assets, personal data may be transferred under Art. 6(1)(f)
|
|
132
|
+
{ text: '**Business transfers:** in the event of a merger, acquisition, or sale of assets, personal data may be transferred under Art. 6(1)(f). You will be notified before it becomes subject to a different privacy policy.' },
|
|
133
133
|
],
|
|
134
134
|
},
|
|
135
135
|
],
|
|
@@ -180,7 +180,7 @@ exports.PRIVACY_SECTIONS = [
|
|
|
180
180
|
{ text: '**Right to object (Art. 21):** object to processing based on legitimate interests. We will cease unless we demonstrate compelling legitimate grounds.' },
|
|
181
181
|
{ text: '**Right to withdraw consent (Art. 7(3)):** where processing is based on your consent (analytics cookies, marketing emails), you may withdraw it at any time without affecting the lawfulness of prior processing. Marketing-email consent can be withdrawn at any time via the unsubscribe link in any marketing email or by contacting us at {EMAIL}.' },
|
|
182
182
|
{ text: '**Automated decision-making (Art. 22):** we do not make any decision producing legal or similarly significant effects concerning you based solely on automated processing.' },
|
|
183
|
-
{ text: '**Right to lodge a complaint (Art. 77):** you have the right to lodge a complaint with the Polish supervisory authority
|
|
183
|
+
{ text: '**Right to lodge a complaint (Art. 77):** you have the right to lodge a complaint with the Polish supervisory authority, Urząd Ochrony Danych Osobowych (UODO), ul. Stawki 2, 00-193 Warszawa, https://uodo.gov.pl, if you believe we are processing your personal data in violation of the GDPR.' },
|
|
184
184
|
],
|
|
185
185
|
},
|
|
186
186
|
{ kind: 'note', label: 'Mandatory vs. optional data', text: 'Providing certain personal data (email address, name, account credentials) is a contractual requirement for accessing the Service, without it, we cannot create or maintain your account. Other fields (such as phone number) are voluntary. Connecting social media accounts via OAuth is optional but required to access publishing, analytics, and inbox features. Marketing-email consent is entirely optional and never a condition of using the Service.' },
|
|
@@ -194,9 +194,9 @@ exports.PRIVACY_SECTIONS = [
|
|
|
194
194
|
{
|
|
195
195
|
kind: 'ul',
|
|
196
196
|
items: [
|
|
197
|
-
{ text: '**Strictly necessary cookies:** required for authentication sessions and core platform functionality. Cannot be disabled without breaking the Service. Legal basis: Art. 6(1)(b)
|
|
197
|
+
{ text: '**Strictly necessary cookies:** required for authentication sessions and core platform functionality. Cannot be disabled without breaking the Service. Legal basis: Art. 6(1)(b), contract performance; no consent required. Duration: session cookies expire when you close your browser; authentication cookies expire after 30 days of inactivity.' },
|
|
198
198
|
{ text: '**Functional cookies:** set only in direct response to an action you take (e.g. selecting a language or theme preference), and strictly necessary to deliver that specific function you have requested. They do not track you across sessions beyond preserving your chosen setting. Legal basis: strictly necessary to fulfil your explicit request under Art. 173 of the Polish Telecommunications Act (ePrivacy); no separate consent required. Duration: up to 12 months, or cleared when you clear your browser data.' },
|
|
199
|
-
{ text: '**Analytics cookies (PostHog):** collect usage event data in pseudonymised form (other than the identifying flows described in Section 6), enable session replay (with form-field values masked; see Section 3), and capture error reports to help us understand and improve how the Service is used. Legal basis: Art. 6(1)(a)
|
|
199
|
+
{ text: '**Analytics cookies (PostHog):** collect usage event data in pseudonymised form (other than the identifying flows described in Section 6), enable session replay (with form-field values masked; see Section 3), and capture error reports to help us understand and improve how the Service is used. Legal basis: Art. 6(1)(a), consent. **No analytics cookies are set and no analytics events are captured before you make a choice** in the cookie consent banner shown on first visit. If you accept, PostHog sets a first-party cookie (name beginning `ph_`) on the `ad2.app` domain, valid for up to 1 year, shared between our website and the app so you are not asked twice. If you decline, no analytics cookie is set and no events are collected. Analytics data is processed on PostHog Cloud EU servers in Frankfurt, Germany (see Section 6).' },
|
|
200
200
|
],
|
|
201
201
|
},
|
|
202
202
|
{ kind: 'p', text: 'You may withdraw or update your cookie consent at any time via the "Cookie settings" link in the footer of our website, or on this Privacy Policy page in the app. Withdrawing analytics consent does not affect platform functionality.' },
|
|
@@ -212,15 +212,15 @@ exports.PRIVACY_SECTIONS = [
|
|
|
212
212
|
{
|
|
213
213
|
kind: 'ul',
|
|
214
214
|
items: [
|
|
215
|
-
{ text: 'Encryption in transit (TLS 1.2+).' },
|
|
216
|
-
{ text: 'Hashed storage of passwords using bcrypt with appropriate cost factors.' },
|
|
217
|
-
{ text: '
|
|
215
|
+
{ text: 'Encryption in transit (TLS 1.2+) on every connection, enforced by our hosting and database providers.' },
|
|
216
|
+
{ text: 'Hashed storage of passwords using bcrypt with appropriate cost factors. Where you sign in with Google, we never receive a password at all.' },
|
|
217
|
+
{ text: 'OAuth tokens we hold directly are encrypted at rest (AES via a server-side key that is never stored beside the data); tokens held by our publishing processor Zernio are subject to Zernio\'s own security measures under our Data Processing Agreement' },
|
|
218
218
|
{ text: 'Server-enforced access grants for third-party tools you authorize via MCP (Section 6a): every request is checked against the access you approved, and grants are individually revocable.' },
|
|
219
|
-
{ text: '
|
|
220
|
-
{ text: 'Pseudonymisation of analytics and usage data where technically feasible.' },
|
|
221
|
-
{ text: '
|
|
222
|
-
{ text: 'Incident detection, response, and escalation procedures
|
|
223
|
-
{ text: '
|
|
219
|
+
{ text: 'Access to production systems is limited to the two people who operate ad2app, each through their own provider account. Every request to a protected part of the Service is authenticated and checked against the account making it, request rates are limited to blunt automated abuse, all input is validated at the API boundary, and our cross-origin policy fails closed, so an unlisted origin is refused rather than allowed. We do not keep a separate application-level audit log of staff access; the logs kept by our hosting, database and payment providers are what we rely on.' },
|
|
220
|
+
{ text: 'Pseudonymisation of analytics and usage data where technically feasible, and masking of text in session recordings, so message and comment bodies are not captured (see Section 3).' },
|
|
221
|
+
{ text: 'Automated dependency vulnerability scanning; secret scanning before any code is committed; a required review of every change by a second person before it reaches production; and automated test, type and database-schema checks that must pass before a deploy. Our deploy also refuses to build if a required configuration secret is missing, so a misconfigured environment cannot silently reach production. **We do not commission external penetration tests.** For a two-person company we judge that proportionate to the risk under Art. 32 GDPR, and we will update this page if that changes.' },
|
|
222
|
+
{ text: 'Incident detection, response, and escalation procedures, including UODO notification within 72 hours of a qualifying breach under Art. 33 GDPR, and notification to affected data subjects where required under Art. 34 GDPR.' },
|
|
223
|
+
{ text: 'Our database provider takes continuous backups with point-in-time recovery, which is what a restore would use, and deleted accounts are held for 30 days before being purged so an accidental deletion can be undone. **We have not yet run a full restore drill**, so we do not claim a tested recovery time.' },
|
|
224
224
|
],
|
|
225
225
|
},
|
|
226
226
|
],
|
|
@@ -230,7 +230,7 @@ exports.PRIVACY_SECTIONS = [
|
|
|
230
230
|
title: '11. Third-Party Links, Social Platforms, and Inbox Data',
|
|
231
231
|
blocks: [
|
|
232
232
|
{ kind: 'p', text: 'The Service allows you to connect the social media accounts you choose to enable platform features. Supported platforms currently include Instagram, TikTok, X (Twitter), YouTube, LinkedIn, Facebook, Threads, Pinterest, Reddit, and Bluesky. When you authorise an OAuth connection, ad2app receives data from that platform\'s API as permitted by your OAuth consent screen. The source of all such data is the respective social media platform\'s API.' },
|
|
233
|
-
{ kind: 'p', text: '**Inbox data and third-party communications:** when you use the inbox features, direct message conversations and post comments from your connected social media accounts are fetched and stored. This includes messages and comments sent by your followers and other third parties on those platforms. Some of this data (for example public post comments) originates from publicly accessible sources on the connected platform; direct messages do not. Those individuals have not directly provided their data to ad2app. We process this data under Art. 6(1)(b) (to provide the inbox feature you have contracted for) and rely on the exemption in Art. 14(5)(b) GDPR
|
|
233
|
+
{ kind: 'p', text: '**Inbox data and third-party communications:** when you use the inbox features, direct message conversations and post comments from your connected social media accounts are fetched and stored. This includes messages and comments sent by your followers and other third parties on those platforms. Some of this data (for example public post comments) originates from publicly accessible sources on the connected platform; direct messages do not. Those individuals have not directly provided their data to ad2app. We process this data under Art. 6(1)(b) (to provide the inbox feature you have contracted for) and rely on the exemption in Art. 14(5)(b) GDPR: providing individual notice to each such person would require disproportionate effort given the volume and platform-derived nature of the data. In line with Art. 14(5)(b), and having regard to the number of individuals concerned, the age of the data, and the safeguards applied, we take appropriate measures to protect these individuals\' rights, freedoms, and legitimate interests, including by making this information publicly available in this policy and by handling any rights request from such a person received at {EMAIL}; our balancing assessment is documented in our Record of Processing Activities (Art. 30 GDPR). Inbox data is not used for profiling, advertising, or any purpose beyond displaying your social media communications within the platform.' },
|
|
234
234
|
{ kind: 'p', text: '**Audience data (Art. 14 GDPR):** when you connect a social media account, the connected platform may provide aggregate audience data (e.g. demographic statistics about your followers). This data originates from the social platform and relates to individuals who are not in a direct relationship with ad2app. It is processed solely as anonymous, aggregate statistics and does not identify any individual; it is therefore not personal data within the meaning of the GDPR (Recital 26) and Art. 14 does not apply to it. Insofar as any element of this data were nevertheless treated as personal data, we would rely on the exemption in Art. 14(5)(b) GDPR (disproportionate effort) and discharge our obligation by making this information publicly available in this policy. Audience data is not used for any other purpose.' },
|
|
235
235
|
{ kind: 'p', text: 'We are not responsible for the privacy practices of third-party social platforms. Please review their privacy policies before connecting your accounts.' },
|
|
236
236
|
],
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { LegalSection } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* Polish version of the Privacy Policy.
|
|
4
|
+
*
|
|
5
|
+
* Structural parity with `PRIVACY_SECTIONS` (./privacy.ts) is load-bearing: the
|
|
6
|
+
* same section ids in the same order, the same block kinds, and the same number
|
|
7
|
+
* of list items and table rows. A document-level parity test asserts the ids,
|
|
8
|
+
* so a drifting translation fails the build rather than silently serving a
|
|
9
|
+
* shorter policy to Polish consumers.
|
|
10
|
+
*
|
|
11
|
+
* Inline markup ({EMAIL}, `code`, **bold**) and proper nouns are carried over
|
|
12
|
+
* verbatim. Legal instruments use their Polish official names (RODO, UODO).
|
|
13
|
+
*/
|
|
14
|
+
export declare const PRIVACY_SECTIONS_PL: LegalSection[];
|