Annex II: Technical and Organizational Security Measures
Data Processing Agreement between [CUSTOMER] and [PLATFORM PROVIDER]Last Updated: [DATE]
Introduction
This Annex describes the technical and organizational measures implemented by [PLATFORM PROVIDER] to ensure a level of security appropriate to the risk, in compliance with GDPR Article 32.
Risk Assessment: [PLATFORM PROVIDER] has conducted a risk assessment considering:
- Likelihood and severity of risks to Data Subject rights and freedoms
- State of the art in data protection technology
- Costs of implementation
- Nature, scope, context, and purposes of processing
- Categories of Personal Data processed (name, email, behavioral data, IP addresses)
Classification: The Personal Data processed is considered medium risk (not special categories, but systematic behavioral monitoring at scale).
1. Technical Security Measures
1.1 Encryption
1.1.1 Encryption in Transit
- TLS 1.2+ for all external communications:
- Public website (events.{domain}) → HTTPS enforced
- Attendee app (live.{domain}) → HTTPS enforced
- Dashboard (dashboard.{domain}) → HTTPS enforced
- Go API → HTTPS enforced
- Firebase SDK connections → TLS 1.2+
- Cipher suites: Only strong ciphers enabled (AES-256, ChaCha20), weak ciphers disabled (RC4, DES)
- Certificate management: Let's Encrypt auto-renewal for web apps, Railway managed certificates
- HSTS (HTTP Strict Transport Security): Set explicitly on Go API responses; Railway and Firebase Hosting enforce HTTPS and set HSTS headers on managed domains by default
- Response security headers: every Go API response carries
X-Content-Type-Options: nosniff,X-Frame-Options: DENY,Referrer-Policy: strict-origin-when-cross-origin, aPermissions-Policydenying camera, microphone, geolocation, payment and USB access,X-XSS-Protection: 0,X-DNS-Prefetch-Control: off,Cache-Control: no-store, no-cache, private,Strict-Transport-Security: max-age=31536000; includeSubDomains, and a Content-Security-Policy (default-src 'none'; frame-ancestors 'none'on API routes; elsewhere a policy restricting scripts, styles, images, fonts and connections to the same origin)
Transport exception — transactional SMS. Messages are submitted to the messaging provider over TLS, but as an HTTP GET request in which the account username, the account password, the recipient's telephone number in plaintext and the full message body are carried as URL query-string parameters. Query-string parameters are conventionally recorded in web-server access logs, so these values should be assumed to be present in the provider's logs notwithstanding the encrypted transport. Transport encryption alone therefore does not protect this path.
External resources referenced by generated landing pages. The prompts used for AI landing-page generation instruct the model to reference cdn.tailwindcss.com and unpkg.com. Both references are compiled away or inlined at publication, so a published landing page does not fetch them and neither host is a sub-processor. The Tailwind compilation step fails open: where the compiler binary is absent from the runtime image the step is skipped with a warning, in which case the reference would survive into the published page and be fetched by every visitor. Separately, the dashboard's page-preview panel loads cdn.tailwindcss.com in the staff member's browser while a page is being edited, which discloses that staff member's IP address and user agent to that content-delivery network.
1.1.2 Encryption at Rest
- PostgreSQL database (Railway):
- Full disk encryption (AES-256)
- Automated backups encrypted with separate key
- Also holds the full system prompt, user prompt, custom instructions and model output of every AI generation, together with the identifier of the member of staff who started it (see §2.6)
- Firestore (Google Cloud):
- Default encryption at rest (AES-256, Google-managed keys)
- Option for Customer-Managed Encryption Keys (CMEK) available upon request
- Firebase Cloud Storage:
- Default encryption at rest (AES-256)
- Landing-page markup, the organisation media library, branding assets, page templates and webinar and offer imagery encrypted in storage buckets. See §1.4 for the access rules applying to these objects
- Google Secret Manager:
- Per-organisation third-party integration credentials — Meta, Cloudflare, NewsmanApp SRL and SendSMS.ro — encrypted with envelope encryption (DEK + KEK). Google Secret Manager is used for these credentials only; platform-level secrets are held as hosting-platform environment variables (see §1.8)
- Google-managed encryption keys with automatic rotation (managed by Google Cloud infrastructure)
- Third-party API credentials are updated by org admins via the dashboard when rotated at the provider
Backups: All database backups retained for 30 days, encrypted separately from production data. ⚠️ The retention figure is not evidenced in [PLATFORM PROVIDER]'s records and must be confirmed against the hosting provider's actual configuration.
1.1.3 Pseudonymization
- Email hashing: No PostgreSQL table holds a plaintext email address, telephone number or personal name. Contacts are keyed by an SHA-256 hash of the lowercased, trimmed email address, and plaintext contact details are held only in Firestore at
orgs/{orgId}/contacts/{emailHash}/pii/private. - Actor IDs: Firebase Anonymous Auth generates pseudonymous identifiers for Realtime Database actors. The actor identifier is nonetheless linked to the contact's identity within the Realtime Database: an identity cache at
live/{sessionId}/identityCache/{actorId}maps the actor identifier to the contact's email hash together with the organisation, webinar and registration identifiers. The plaintext email address itself is not written to the Realtime Database.
Two exceptions apply. First, the automations engine records the outcome of each executed step as a JSON document in PostgreSQL, and for email and SMS steps that document includes the recipient's plaintext email address or telephone number; those records are removed when the contact is deleted, by cascade, but they are not otherwise pseudonymised. Second, the ai_jobs table stores the full prompt text of each AI generation, which may contain an approved attendee testimonial together with the name and company recorded on it; those rows carry no contact link and are not removed on erasure.
The API holds an in-process cache of plaintext contact details (email address, name and telephone number), keyed by organisation and email hash, to avoid repeated Firestore reads. The cache has no expiry, and entries are invalidated only within the process that performs the write. Where more than one API instance is running, a correction or a deletion applied on one instance does not evict the copy held by another.
Limitation: Hashing is reversible if attacker has original email (rainbow table), so we also rely on access controls and encryption.
GAP-SEC-03 · CODE — KNOWN GAP, REMEDIATION PENDING
This Annex previously stated that plaintext personal data is stored only in Firestore and that Realtime Database actor identifiers are not linked to an email address. PostgreSQL additionally holds plaintext email addresses and telephone numbers inside automation step-execution results, the API tier holds an unexpiring in-process cache of plaintext contact details, and the Realtime Database identity cache links each actor identifier to the contact's email hash. This divergence is recorded on the compliance remediation register and is under review.
1.2 Access Control and Authentication
1.2.1 Staff Access to Production Systems
Multi-Factor Authentication (MFA):
- Required for [PLATFORM PROVIDER]'s own accounts on third-party providers (Firebase Console, Railway, GitHub, Google Cloud)
- TOTP-based (Google Authenticator, Authy) or hardware tokens (YubiKey)
- ⚠️ This is an internal administrative practice on third-party consoles and is not a control of the Services. The Services themselves provide no multi-factor or two-factor authentication: Customer dashboard users sign in with an email address and password or with Google OAuth, and authentication is single-factor. The four-digit one-time code described under "Mobile App Attendees" below is an alternative to the attendee magic link, not a second factor
Role-Based Access Control (RBAC):
- Firebase Console: Admin (full control), Viewer (read-only)
- Railway: Admin (deploy, env vars), Developer (deploy only), Viewer (logs only)
- PostgreSQL:
api_user(RLS-enforced, read/write scoped byorg_id),scheduler_user(superuser for cron jobs),admin_user(DBA, break-glass only). Theapi_userrole is provisioned out of band by a setup script; no migration creates it, so the role and its privileges are not reproducible from the migration set alone - Dashboard (Customer Users): four roles —
admin,moderator,marketerandstaff— described immediately below
Dashboard Roles:
The platform defines four staff roles — admin, moderator, marketer and staff — mapped to three permission groups (marketing, live, settings). staff holds no permission group and is effectively read-only; marketer holds the marketing group; moderator holds the live group; admin holds all three. A role is chosen explicitly when the account is created; there is no read-only default. Administrator privileges are required for exactly one endpoint, the audit-log listing. Every other destructive action — deleting webinars, sessions, funnels, segments, pages, offers, polls, uploads and testimonials — is authorised by the marketing or live permission group, which the non-administrator marketer and moderator roles satisfy.
GAP-GOV-05 · GOVERNANCE — KNOWN GAP, REMEDIATION PENDING
This Annex previously described a two-role dashboard model comprising an administrator with full access and a read-only staff role, and stated at §2.7 that new staff users receive the read-only role by default. The platform defines four roles, the role is selected explicitly at account creation with no read-only default, and every destructive operation other than reading the audit log is authorised by permission group rather than by administrator status. This divergence is recorded on the compliance remediation register and is under review.
Principle of Least Privilege:
- Engineers have access only to services they maintain
- Support staff have read-only access (cannot modify data)
- Database admin credentials stored in password manager (1Password), rotated every 90 days
1.2.2 End-User Authentication
Event Attendees (Web):
- Anonymous authentication (no password, no account)
- registrationId (UUID) grants access (stored in localStorage)
- Rate limiting on the public API, keyed on the authenticated user where one is present and otherwise on the client IP address — never on the email address. The limit is set by operator-configurable environment variables and currently stands at 1,200 requests per minute with a burst of 300; because it is operator-tunable, the figure in force at any time is a configuration value rather than a contractual commitment. Buckets are held in each API process's memory, so limits do not aggregate across instances and are reset by every restart or deployment. Requests whose apparent origin is a private network address bypass the limiter
Mobile App Attendees:
- Email link (magic link) authentication via Firebase Auth (API-proxied — the mobile app does not include the events Firebase SDK; auth operations are handled server-side by the Go API)
- Firebase Auth JWT (idToken) obtained after email link verification; expires after 1 hour
- Refresh token (refreshToken) used to obtain new idTokens without re-authentication
- Token storage: idToken + refreshToken stored in platform-secure storage — iOS Keychain / Android EncryptedSharedPreferences — never in plain SharedPreferences, UserDefaults, or unencrypted localStorage
- Proactive refresh: Mobile app checks token expiry before each request (refreshes proactively if expiring within 5 minutes). On 401 response, refresh is attempted once; if refresh fails (revoked token), stored tokens are cleared and user is prompted to re-authenticate
- Rate limiting: attendee authentication endpoints are limited per IP address, or per authenticated user where one is present — never per email address. Magic-link sending is limited to 10 requests per minute with a burst of 3; link verification and code verification to 10 per minute with a burst of 5 each; token refresh to 30 per minute with a burst of 5
- oobCode expiry: Magic link codes are single-use with 1-hour expiry (Firebase Auth enforced)
- Email one-time code fallback: where the magic link cannot be used, a numeric code is emailed instead. The code is four digits, drawn from a cryptographically secure random source, valid for 10 minutes, and invalidated after three failed attempts. One code is held per email address at a time. Beyond the per-IP limits above there is no per-address throttle on code verification
- App store review demo account: a single named demo account is provisioned so that mobile application stores can review the application. Where, and only where, both the demo address and the demo code are set as environment variables, a sign-in request matching that exact address and code is accepted without the stored-code checks and without the per-account lockout. The address is matched exactly — never by prefix, domain or pattern — the code is compared in constant time, and the mechanism is inert when either variable is unset. The code does not expire and is not rotated automatically. A sign-in through this path is written to the application log but is not recorded in the audit log
Customer Staff:
- Firebase Auth with email/password or Google OAuth
- Custom claims (
org_id,role) enforce org isolation - JWT expiration: 1 hour (auto-refreshed)
- Password policy: minimum six characters where an administrator sets a password directly, which is also Firebase Authentication's own default minimum. No complexity, reuse or rotation requirement is enforced by the platform
Residual risks in the authentication configuration:
- Verification of dashboard tokens is conditional on the Firebase project identifier being present in the environment. Where that variable is absent, the API falls back to a development stub that trusts caller-supplied
X-User-ID,X-Org-IDandX-Roleheaders verbatim. No production assertion prevents this fallback, in contrast to the database connection, where the API refuses to start in production if the restricted connection string is missing. - Where the Firebase Authentication emulator host variable is set, both dashboard and attendee tokens are parsed without signature, expiry or issuer verification, and the attendee path additionally skips the email-verification check.
- Service-to-service authentication accepts any bearer token where the service secret is unset, and in that state grants an administrative context with the organisation taken from a caller-supplied header.
GAP-SEC-02 · CODE — KNOWN GAP, REMEDIATION PENDING
This Annex previously stated that magic-link sending is rate-limited per email address and that staff passwords must be at least eight characters. Neither control exists: rate limiting is keyed on IP address or authenticated user only, and an administrator-set password is accepted at six characters. The three environment-dependent authentication fallbacks described above, and the app store review demo account, were also undisclosed. This divergence is recorded on the compliance remediation register and is under review.
1.3 Network Security
Firewall Rules:
- Railway: Ingress limited to HTTPS (port 443), PostgreSQL (port 5432 internal only)
- Firebase: Managed by Google Cloud (DDoS protection, WAF)
Reverse Proxy and DDoS Protection:
- Cloudflare is a mandatory reverse proxy in front of attendee traffic in production. It terminates TLS for, and therefore sees, every attendee request, including registration submissions carrying a plaintext email address, name and telephone number, and for that traffic the platform takes the client IP address it records or forwards from a Cloudflare-supplied header, which its IP-extraction helper checks before any other proxy header. For this traffic it is not a Customer-optional content-delivery network
- Cloudflare provides L3/L4/L7 DDoS mitigation on the traffic it proxies
- Railway includes basic DDoS protection
- Because both the rate limiter and the recorded client IP address trust the Cloudflare-supplied header, a request reaching the hosting origin without passing through Cloudflare can present an arbitrary value in that header. Restricting origin ingress to Cloudflare is a necessary complement to the rate limiter, and its absence is a residual risk
Bot Protection (Cloudflare Turnstile):
- Cloudflare Turnstile is injected into published landing pages that contain a funnel form, outside the consent bundle. Server-side verification transmits the visitor's IP address to Cloudflare
- Its scope is narrow: it is enforced on funnel form submissions only, and only where the organisation has configured a Turnstile secret. It is not applied to the webinar registration endpoint
- It fails open by design: where the secret cannot be retrieved, or the verification service is unreachable, the submission is accepted
Intrusion Detection:
- Application-level logging (all API requests logged with client IP address, endpoint, status code, latency and request identifier)
- There is no automated intrusion detection, traffic-anomaly alerting or security-event monitoring service in operation. Detection is manual and reactive; see §1.5
Private Networking:
- PostgreSQL accessible only from Railway's internal network (not public internet)
- Firebase Admin SDK authenticated via service account key (not exposed to clients)
1.4 Database Isolation (Row Level Security)
PostgreSQL RLS Policies:
Tenant isolation in PostgreSQL is enforced by Row Level Security. Thirty-two of the thirty-three tables carry an org_id column and have Row Level Security enabled with a policy restricting both reads and inserts to rows whose org_id matches the organisation identifier set on the connection; the single exception is the platform-wide scheduler job-run log, which holds no personal data. The organisation identifier is set with SET LOCAL inside a transaction at the start of every request, and the application connects as a dedicated non-superuser role that Row Level Security applies to. The API refuses to start in production if that dedicated connection string is absent, so the request path cannot fall back to the privileged connection.
Its residual limits are as follows:
- Row Level Security is enabled but not forced. A table owner or superuser connection is not subject to the policies, so isolation depends on the application continuing to connect as the restricted role.
- Certain public request paths deliberately use the privileged connection because they must resolve an opaque token before any organisation is known: share-token lookup, funnel tracking-token lookup, funnel step and page-view lookup, and funnel webhook-secret lookup. Row Level Security provides no backstop on those queries.
- The organisation identifier is interpolated into the
SET LOCALstatement as a string rather than bound as a parameter. In normal operation it originates from a verified token claim; under the service-authentication and development-stub paths it originates from a caller-supplied header. - Helper functions for an administrative bypass context exist in the database layer but are unused, and no policy in any migration references the session variable they set, so they confer nothing. There is accordingly no application-level Row Level Security bypass path in use.
Firestore Security Rules:
The Firestore security rules restrict organisation configuration, staff user records, page records, private webinars, contact-level consent records and the registration PII subcollection to authenticated members of the owning organisation, and they deny all client access to the top-level collections that hold verification codes and magic links. They do not restrict two categories of personal data:
- Contact PII. The document at
orgs/{orgId}/contacts/{emailHash}/pii/private, which holds the contact's plaintext email address, name and telephone number, may be fetched by any authenticated Firebase user — including any anonymous web attendee and any email-verified mobile user, from any organisation — provided they know the organisation identifier and the email hash. The email hash is an unsalted SHA-256 of the lowercased, trimmed email address, so the document path can be computed directly by anyone who knows the target's address. Listing the collection still requires staff of the owning organisation. - Registration documents. Documents at
orgs/{orgId}/webinars/{webinarId}/sessions/{sessionId}/registrations/{registrationId}are readable without authentication, exposing the registration status, the email hash, the registration timestamp and the registration metadata. The rule grantsread, which covers both individual fetches and collection listings, notwithstanding an inline comment in the rules file stating that listing requires staff. Registration documents may also be created without authentication, which is how the public registration form works.
Session documents, non-private webinar documents, polls, offers and testimonials are likewise publicly readable, and testimonials and abuse reports are publicly creatable, by design.
GAP-ISO-02 · CONFIG — KNOWN GAP, REMEDIATION PENDING
This Annex previously stated that all Firestore collections are nested under an organisation path, that the rules compare the caller's organisation claim against the organisation identifier, and that registration documents are readable only by staff of the same organisation. Contact personal-data documents are readable by any authenticated Firebase user who knows the organisation identifier and the email hash, registration documents are readable without authentication, and the collections holding verification codes and magic links sit outside the organisation tree, accessible to server components only. This divergence is recorded on the compliance remediation register and is under review.
RTDB Security Rules:
Access to live-session data in the Realtime Database is authorised by the role claim in the caller's authentication token alone. The security rules contain no organisation identifier and make no comparison between the caller's organisation and the organisation that owns the session, so an authenticated dashboard user holding any of the admin, moderator, marketer or staff roles — in any organisation on the platform — can read any live session's data given only its session identifier. This includes the chat stream, the moderated-message stream, presence, attendance, presence timelines, per-actor message counts, offer clicks, feedback responses and the identity cache that maps an attendee's anonymous actor identifier to the hash of their email address. Separately, the chat stream, the actor directory (which holds attendee display names), the banned and muted actor lists, the feedback definition and the tracked-link table are readable by any authenticated user, which includes every anonymous attendee of every session. All organisations share a single Firebase project per environment, so a single rule set governs the whole platform.
The one control in the previous description that does hold is the attendee write restriction: an attendee may write only to the nodes keyed by their own actor identifier, and an actor on the session's banned list is prevented from writing at the rule level.
GAP-ISO-01 · CONFIG — KNOWN GAP, REMEDIATION PENDING
This annex previously described tenant isolation in the live-session database as equivalent to the organisation-level isolation enforced in PostgreSQL. The Realtime Database security rules contain no organisation identifier and authorise staff-privileged reads solely on the role claim in the caller's token, so an authenticated dashboard user of any organisation who knows a session identifier can read that session's live data. Organisation-level isolation in PostgreSQL, described above, is unaffected. This divergence is recorded on the compliance remediation register and is under review.
Cloud Storage Security Rules:
The Cloud Storage security rules grant unconditional public read access to all seven organisation-scoped paths — webinars/, pages/, offers/, media/, page_templates/, branding/ and staff/ — so any object stored under an organisation's prefix is readable by anyone who knows or can guess its path, without authentication. Write access on those same paths requires only that the caller be authenticated; the organisation identifier in the path is never compared against the caller's token, so an authenticated user of one organisation can overwrite another organisation's branding, media, page templates and landing-page files. A final catch-all rule grants read and write access to every remaining object in the bucket to any authenticated user, which includes every anonymous attendee.
The bucket holds more than landing-page markup: the organisation media library, branding assets, page templates and webinar and offer imagery are stored under the same prefixes, and those assets may depict identifiable individuals. Article 17 erasure does not currently reach stored objects.
Testing: there is no automated test of tenant isolation. Automated test coverage in the API is limited to five unit-test files covering email-tracking handlers, email utilities, tracked-link redirects and page-utility helpers; no automated test exercises Row Level Security, authentication, authorisation or tenant isolation, and no script anywhere simulates a cross-organisation query.
GAP-PROC-04 · PROCESS — KNOWN GAP, REMEDIATION PENDING
This Annex previously stated that Row Level Security policies are tested with automated scripts that simulate cross-organisation queries and verify that no rows are returned. No such test or script exists. This divergence is recorded on the compliance remediation register and is under review.
1.5 Logging and Monitoring
Application Logs:
- Each API request is logged with: timestamp, HTTP method, request path including its query string, status code, latency, client IP address and request identifier. The access log does not record the organisation identifier, the acting user or the user agent. Attribution of a staff action to a user and an organisation is available from the audit log described below, not from the access log
- Logs retained for 90 days
- Personal data does appear in the application logs. Plaintext email addresses are written by the attendee authentication, bulk import, staff user management and funnel submission paths; the recipient's plaintext telephone number is written when an automation SMS fails; and because the access logger appends the raw query string to the logged path, the funnel webhook secret — which is supplied as a query parameter — is recorded on every inbound webhook call
GAP-SEC-03 · CODE — KNOWN GAP, REMEDIATION PENDING
This Annex previously stated that the application logs contain no personal data, only email hashes, and that every request is logged with its organisation identifier, its user identifier and its user agent. Plaintext email addresses, plaintext telephone numbers and a webhook credential are written to the application logs, and the access-log record contains none of those three attribution fields. This divergence is recorded on the compliance remediation register and is under review.
Audit Logs (PII Access):
- An entry is recorded in the
audit_logtable for every staff-initiated write across the dashboard API — approximately seventy distinct actions covering the creation, modification and deletion of webinars, sessions, funnels, pages, offers, polls, segments, automations, media and integrations — and for personal-data operations including contact and segment exports, registration imports, moderation actions, changes to retention settings, the creation and removal of staff accounts, and the processing of data-subject requests. Public, attendee, service and webhook endpoints are outside the audit scope by design - Each entry records: organisation, acting user, that user's role, the action, the target type and identifier, JSON metadata, the acting user's IP address, the user agent and the request identifier
- The table is append-only at the database-privilege level: the application's database role holds only
SELECTandINSERTon it, and noUPDATEorDELETE - Retention: no automated deletion. The audit log is not among the data types the retention job recognises, and nothing else in the platform deletes from it, so it grows without limit. The same applies to the data-subject request register. Entries created by the data-subject rights workflow record the subject's email hash in their metadata, so an erased subject's email hash remains in the audit log after erasure. Because the application's database role holds no delete privilege, the audit log cannot be purged through the application's connection either
GAP-RET-05 · CODE — KNOWN GAP, REMEDIATION PENDING
This Annex previously stated that audit-log entries are retained for two years. No retention period is enforced on the audit log or on the data-subject request register; both are retained indefinitely, and they hold the acting staff member's IP address and, in some entries, the data subject's email hash. This divergence is recorded on the compliance remediation register and is under review.
Security Monitoring:
- Firebase Authentication applies its own automatic throttling to repeated failed sign-in attempts; the threshold is set by Google and is not configured by the platform
- There is no detection of unusual API patterns, no anomaly detection on data-subject request volumes and no monitoring of database connection behaviour
Alerting:
The platform emits structured application logs to standard output, which the hosting provider retains and makes searchable, and exposes an administrator-only system-health endpoint reporting request counters and database read counters. Those counters are held in process memory and reset on every restart or deployment. There is no error-tracking service, no on-call paging integration and no automated alerting: incident detection depends on a person observing logs, the health endpoint or a customer report.
GAP-PROC-02 · PROCESS — KNOWN GAP, REMEDIATION PENDING
This Annex previously described email alerts to the engineering team for critical errors, a messaging integration for security incidents, a paging rotation for production outages and automated detection of unusual API patterns and database connection spikes. No error-tracking, alerting or paging integration exists, and no automated detection of any of those conditions is in operation. This divergence is recorded on the compliance remediation register and is under review.
1.6 Vulnerability Management
Vulnerability management. Dependency and vulnerability scanning is performed manually. There is no continuous integration pipeline in the repository, no automated dependency-update service and no automated security scanning of commits, dependencies or container images. Vulnerabilities are identified through manual review of dependency advisories and through the security notices published by the hosting providers and the framework maintainers, and are remediated by a developer raising and deploying the change directly.
GAP-PROC-03 · PROCESS — KNOWN GAP, REMEDIATION PENDING
This Annex previously stated that an automated dependency-update service raises pull requests for security updates, that a dependency audit runs on every continuous-integration build and fails the build on high-severity findings, and that Go module vulnerability scanning runs weekly. No continuous-integration configuration, dependency-update configuration or scanning configuration of any kind exists, and none of those controls runs. This divergence is recorded on the compliance remediation register and is under review.
Penetration Testing:
- Annual penetration test by independent security firm (planned for [Q4 2026])
- Bug bounty program (future, post-ISO 27001)
Patch Management:
- Critical vulnerabilities: Patched within 7 days
- High vulnerabilities: Patched within 30 days
- Medium/Low vulnerabilities: Patched within 90 days or next release cycle
Code Review:
- Changes are reviewed by the engineering team before deployment, and security-sensitive changes (authentication, Row Level Security, encryption) are reviewed with particular care. Peer review is a working practice rather than an enforced gate: no configuration present in the repository requires a review before merge, and none can be evidenced from it. See §1.8
1.7 Backup and Disaster Recovery
PostgreSQL Backups (Railway):
- Automated daily backups (retained 30 days)
- Point-in-time recovery (PITR) within retention window
- Backups encrypted with separate key
- Geo-replicated to different EU region (disaster recovery)
Firestore Backups:
- Google Cloud Firestore automatic daily backups
- Point-in-time recovery within 7 days
- Manual exports to Cloud Storage (weekly)
RTDB:
- No backups are taken of the Realtime Database
- Poll and offer definitions also exist in Firestore. Questions submitted during a session exist only in the Realtime Database and have no Firestore counterpart
Live-session data in the Realtime Database is retained indefinitely. There is no scheduled cleanup function: the Cloud Functions codebase exports ten functions, of which nine are database triggers and one is a minutely presence reconciler, and none deletes session data. Moving a session to replay or archived status does not prune it either — the lifecycle job writes a statistics snapshot to Firestore and performs no deletion in the Realtime Database. The only operations that remove a live-session node are the manual deletion of a session and the manual deletion of the parent webinar. Chat message text, attendee display names, presence and attendance records, poll votes, reactions, offer clicks and feedback responses therefore persist for the lifetime of the webinar record.
GAP-RET-02 · CODE — KNOWN GAP, REMEDIATION PENDING
This Annex previously described Realtime Database session data as ephemeral and confined to the session. No scheduled cleanup function exists and archiving a session does not remove its data: live-session records — chat message text, attendee display names, presence, attendance, poll votes, reactions, offer clicks and feedback — are removed only when a staff member deletes the session or the parent webinar. This divergence is recorded on the compliance remediation register and is under review.
Recovery Time Objective (RTO): 4 hours for full service restoration Recovery Point Objective (RPO): 24 hours (maximum data loss = 1 day since last backup)
Testing: ⚠️ These are objectives, not validated figures. No restore runbook is maintained, no restore has been performed and timed against production data, and no scheduled job exercises one, so recovery must be treated as best-effort until a timed restore has been carried out. The same position is recorded at Section 4.3 of the Data Breach Response Plan.
GAP-PROC-04 · PROCESS — KNOWN GAP, REMEDIATION PENDING
This Annex previously stated that the disaster recovery plan is tested annually by restoring backups to a staging environment, and presented the four-hour recovery time objective and the twenty-four-hour recovery point objective as validated commitments. No documented restore procedure exists, no restore has been performed and timed against production data, and no record of any such exercise is held. This divergence is recorded on the compliance remediation register and is under review.
1.8 Secure Development Lifecycle
Code Repository:
- GitHub (private repositories)
- No branch-protection or review-enforcement configuration is present in the repository; deployment is triggered by a push to the deployed branch
Development and Deployment:
Secure development lifecycle. Changes are authored and reviewed by the engineering team and verified locally using the repository's lint, vet, type-check and build targets before deployment. There is no automated pipeline that enforces those checks: no continuous integration configuration exists in the repository, so the checks are advisory and depend on the developer running them. Automated test coverage is limited to five unit-test files in the Go API covering email-tracking handlers, email utilities, tracked-link redirects and page-utility helpers; there are no automated tests covering authentication, authorisation, Row Level Security or tenant isolation, and no automated test simulates a cross-organisation query.
GAP-PROC-03 · PROCESS — KNOWN GAP, REMEDIATION PENDING
This Annex previously described a continuous integration and deployment pipeline running automated unit and integration tests on every pull request, static application security testing and dependency checks, a staging deployment gate and a manual production-approval step. No such pipeline exists: the repository contains no continuous integration configuration of any kind, and deployment is triggered directly by a push to the deployed branch. This divergence is recorded on the compliance remediation register and is under review.
Secrets Management:
- Platform-level secrets — the database connection strings, the Firebase service-account credential, the Firebase web API key, the service-to-service secret and the AI provider API key — are held as hosting-platform environment variables, encrypted at rest by the hosting provider
- Google Secret Manager holds per-organisation third-party integration credentials only (Meta, Cloudflare, NewsmanApp SRL, SendSMS.ro)
- Local development secrets in
.env.local(gitignored) - No secrets are committed to the repository
GAP-SEC-04 · CONFIG — KNOWN GAP, REMEDIATION PENDING
This Annex previously stated that no secrets are held in environment variables and that production secrets are held in Google Secret Manager. Every platform-level secret, including the Firebase service-account credential and the AI provider API key, is read from a hosting-platform environment variable; Google Secret Manager is used only for per-organisation third-party integration credentials. This divergence is recorded on the compliance remediation register and is under review.
2. Organizational Security Measures
2.1 Staff Training and Awareness
Status. No staff data-protection training programme has been established, and no training, attendance or completion record is held. [PLATFORM PROVIDER]'s internal compliance register lists staff GDPR training as an outstanding action. The measures set out below are accordingly the intended programme, not controls presently in operation, and no training record can be produced in response to a Customer audit request under the Data Processing Agreement.
Intended GDPR Training:
- All engineers, support, and management complete GDPR training within 30 days of hire
- Annual refresher training (1 hour, mandatory)
- Topics: GDPR principles, Data Subject rights, consent, breach notification, secure coding
Intended Security Awareness:
- Phishing simulation quarterly (tests staff ability to identify malicious emails)
- Password hygiene (use of password manager mandatory)
- Social engineering awareness (verify requests for data access)
Intended Specialized Training:
- Database admins: RLS configuration, backup restoration
- Frontend engineers: Secure storage (avoid PII in localStorage), XSS prevention
- Backend engineers: SQL injection, authentication bypass, authorization bugs
GAP-PROC-05 · PROCESS — KNOWN GAP, REMEDIATION PENDING
This Annex previously presented the training and awareness programme in this section as established and mandatory, and the Data Processing Agreement offers staff training records as evidence inspectable on a Customer audit. No training programme has been established and no training records exist, so that evidence cannot be produced. This divergence is recorded on the compliance remediation register and is under review.
2.2 Confidentiality and Background Checks
Confidentiality Agreements:
- All staff sign NDAs before accessing production systems
- NDAs survive termination indefinitely
- Contractors and consultants sign separate DPAs if they process Personal Data
Background Checks:
- Criminal background checks for staff with production database access (to extent permitted by Romanian law)
- Reference checks for all hires
2.3 Access Management Lifecycle
Onboarding:
- Manager requests access (Jira ticket, approved by CTO)
- IT provisions accounts (Firebase, Railway, GitHub)
- MFA enabled before first login
- Staff completes GDPR training before production access — see §2.1: no training programme is presently established, so this step is not operative
Offboarding:
- Manager notifies IT within 24 hours of termination
- IT revokes all access (Firebase, Railway, GitHub, email) immediately
- Devices returned and wiped
- Audit log reviewed for suspicious activity in final 30 days
Access Review:
- Quarterly review of all staff access (HR + IT)
- Remove unused accounts (no login in 90 days)
- Downgrade over-privileged accounts
2.4 Vendor Management
New Sub-Processor Checklist:
- Request vendor's DPA (must comply with GDPR Art 28)
- Request sub-processor list (if vendor is itself a processor)
- Verify security certifications (ISO 27001, SOC 2, or equivalent)
- Confirm data location (EU preferred, US acceptable with SCCs)
- Assess breach notification SLA (must notify within 24-48 hours)
- Sign DPA before integration
- Add to DPA Annex III (Sub-Processor List)
- Notify customers (30-day objection period)
Compliance status of the checklist. Two sub-processors were brought into production without the checklist being completed. The AI model provider (Anthropic PBC, engaged by [PLATFORM PROVIDER] under a single platform-level credential) and the transactional messaging provider (SendSMS.ro) were both processing personal data before either was added to Annex III and before any sub-processor change notice was issued, so steps 4, 6, 7 and 8 were not performed for either. Both are now recorded in Annex III.
GAP-CONTRACT-01 · CONTRACT — KNOWN GAP, REMEDIATION PENDING
This Annex presented the new sub-processor checklist as an operative control, and the Data Processing Agreement commits [PLATFORM PROVIDER] to notice before a new sub-processor begins processing. Two sub-processors were engaged and began processing personal data without an executed data processing agreement, without a recorded transfer mechanism where the transfer is to a third country, without being added to Annex III and without the contractual notice being given. This divergence is recorded on the compliance remediation register and is under review.
Annual Vendor Review:
- Review sub-processor DPAs for changes
- Check for security incidents in past year (request certification from vendor)
- Verify certifications remain valid (ISO 27001, SOC 2)
2.5 Incident Response
Incident Response Team:
- Incident Commander: CTO
- Technical Lead: Senior Backend Engineer
- Legal Counsel: External lawyer (on retainer)
- DPO: [Name] (if appointed)
- Communications: CEO (customer notifications)
Incident Response Plan: See separate document: data-breach-response-plan.md
Quarterly Tabletop Exercises:
- Simulate Security Incidents (ransomware, unauthorized access, accidental deletion)
- Test notification procedures (can we notify all customers within 24 hours?)
- Review and update plan based on lessons learned
- ⚠️ No tabletop exercise has been recorded since the Data Breach Response Plan was adopted, so the quarterly cadence stated here is a commitment rather than an established practice. The same position is recorded at Section 5.2 of that plan
2.6 Data Minimization and Retention
Data Minimization Principles:
- Registration requires only email + name (phone optional)
- No collection of special categories (health, religion, etc.)
- Behavioural tracking is recorded in the analytics database only where consented; see §2.7 for the exact scope of that gate
- IP addresses. At webinar registration the IP address is used transiently for geo-enrichment and is not stored; only the derived country and city are retained. Three qualifications apply: the acting staff member's IP address is stored in the audit log and in the scheduler job-run log; a stable pseudonymous visitor identifier derived from the visitor's IP address and user agent is stored for every non-bot visitor to every funnel landing page, without a consent gate and without any retention period; and the visitor's raw IP address and raw user agent are transmitted to Meta and to TikTok on the server-side conversion paths where the organisation has enabled those integrations. The raw user agent string is additionally written into the registration's attribution metadata — held on the funnel entry and on the Firestore registration document — by the registration form's client script, and is read from there when a server-side conversion event is transmitted.
- FCM device tokens are pseudonymous (linked to email_hash, not plaintext email). No PII is embedded in the token itself.
- Telephone numbers are read from Firestore at send time and transmitted to the messaging provider in plaintext; they are never stored in PostgreSQL. See §1.1.1 for the limitation on that transport
- AI-assisted content generation. Where a member of staff initiates a generation, the prompt transmitted to the AI model provider contains the organisation name, the webinar title, description and type, the page brief, staff-authored instructions, staff-uploaded reference images inlined in the request, text extracted from any reference URL supplied by staff, and approved attendee testimonials — the attendee's display name, free-text quote, company and rating. Chat message content, registration records, contact email addresses, telephone numbers, poll answers, attendance data and behavioural events are never sent. The request is made server-side; no attendee device contacts the provider and no cookies are involved. Every system prompt, user prompt, model output and token count is retained in PostgreSQL together with the identifier of the member of staff who started the job, and those records are keyed to an entity rather than to a contact, so they are not reached by the erasure pipeline. No consent is sought from, and no notice given to, the testimonial author for this transmission
GAP-TRACK-01 · CODE — KNOWN GAP, REMEDIATION PENDING
This Annex previously stated that IP addresses are processed transiently for geo-enrichment and are not stored in any database. Staff IP addresses are stored in the audit log and in the scheduler job-run log, a stable IP-derived visitor identifier is stored for every funnel landing-page visitor without a consent gate, and raw IP addresses are transmitted to Meta and TikTok on the server-side conversion paths. This divergence is recorded on the compliance remediation register and is under review.
Retention Policies:
- Retention periods are configured per organisation, and no default policy is seeded. The retention enforcement job acts only on policies that exist, so an organisation that has configured none has no data deleted by age. The retention settings screen currently submits eight data types while the API accepts five, and the API validates the whole submission before writing any of it, so every save attempt is rejected and no retention policy can be configured through the product
- Where an enabled policy would delete more than ten thousand rows in a single run, the job records a warning and deletes nothing, so a table whose backlog has crossed that threshold is not brought back within its retention period by subsequent runs
- Where a policy can be enabled, the configurable range is 30 to 3,650 days
- Contacts: retained for the duration of the business relationship; deleted only on a data subject erasure request or on organisation termination
- Behavioural events: no automatic deletion unless a retention policy is in force
- FCM device tokens: no automated deletion. The retention settings screen offers a 60-day default for this data type, but that value is an unsaved default on a screen that cannot save. Device tokens are nevertheless deleted immediately on an
UNREGISTEREDresponse from the push provider, and on erasure - Push delivery records (
push_sends): deleted on erasure; no age-based deletion in practice, for the reason above - Audit log and data-subject request register: no automated deletion — see §1.5
- Firestore: no time-to-live policy is configured on any Firestore collection. Registration documents and contact PII documents are removed only by an erasure request or by the manual deletion of the parent webinar or session
- Realtime Database: no automated deletion — see §1.7
- Consent records: the current-state consent table is deleted together with the contact record by cascade. The append-only consent event history is not: on erasure its link to the contact is set to null and the row is retained, holding the organisation, webinar and registration identifiers, the purpose, the action, the method, the policy version and the timestamp. It is retained as the Article 7(1) record of how consent was obtained
- Two further tables holding personal data keyed by email hash are not reached by the erasure routine and have no foreign key to the contact record, so they are not removed by cascade either: the SMS delivery log and the segment-broadcast recipient log. A per-person record of SMS messages sent — email hash, webinar and session, template type, tracking code, provider message identifier, delivery status and delivery and click timestamps — therefore persists after an Article 17 erasure, and neither table is included in the Article 15 data export
GAP-RET-01 · CODE — KNOWN GAP, REMEDIATION PENDING
This Annex previously stated that Customers configure per-organisation retention periods in the dashboard, that device tokens are subject to a 60-day rolling retention enforced daily by a scheduled job, and that behavioural events and stale device tokens are deleted automatically. No retention policy can be saved through the product, because the settings screen submits data types the API rejects and the API validates the whole submission before writing any of it; no default policy is seeded; and enforcement additionally halts for any policy whose backlog exceeds ten thousand rows. This divergence is recorded on the compliance remediation register and is under review.
GAP-RET-05 · CODE — KNOWN GAP, REMEDIATION PENDING
This Annex previously stated that consent records are deleted together with the contact record by cascade, with no independent time-based deletion. That holds for the current-state consent table only; the append-only consent event history survives erasure with its link to the contact set to null and is retained indefinitely. This divergence is recorded on the compliance remediation register and is under review.
Data Subject Rights:
- Early deletion available on request (overrides retention policy)
- Audit logs track all deletions
- A GDPR Article 18 processing restriction is enforced consistently as a hard stop: a restricted contact cannot be granted or re-granted any consent, receives no email, SMS or push message, is excluded from contact and segment exports and from segment broadcasts, and no server-side conversion event is sent for them
- Exported files leave the platform's controls. A member of staff holding the marketing permission group can export a segment's members as a file containing each member's plaintext email address and name. The export does not require marketing consent; where the "include flagged" option is used it also returns contacts suppressed for bounce, spam complaint or global opt-out; and contacts who have unsubscribed are always included, because unsubscribing withdraws marketing consent without setting a suppression flag. Contacts subject to an Article 18 restriction are always excluded, and the export itself is recorded in the audit log. The resulting file nevertheless sits outside the platform's retention and erasure pipeline: an erasure request cannot reach it, and responsibility for its handling, storage and deletion rests with the Customer as controller
2.7 Privacy by Design and Default
Privacy by Design Principles:
- Proactive not Reactive: RLS designed before first line of code, consent gate built into Cloud Functions
- Privacy as Default: behavioural tracking is opt-in rather than opt-out and consent checkboxes are not pre-ticked. Consent is nevertheless bundled and, for one purpose, inferred rather than collected per purpose — see "How consent is actually collected and enforced" below
- Privacy Embedded: Security not bolted on — RLS, encryption, pseudonymization are core architecture
- Full Functionality: Privacy does not reduce event features (attendees can fully participate without consent to tracking)
- End-to-End Security: Encryption in transit + at rest + access controls at every layer
- Visibility and Transparency: audit logs, privacy policy in plain language, data export available. The Article 15 export does not reach every store holding the data subject's personal data — see §2.6
- Respect for User Privacy: a GDPR deletion pipeline, and consent withdrawal through the attendee preferences page. Withdrawal is not available on the live watch page, where the cookie banner and the cookie-settings control are removed from the page
How consent is actually collected and enforced:
On the public funnel form a single checkbox records acceptance of both the terms of service and the processing of personal data, and a telephone number entered in the form grants consent to SMS notifications without a separate checkbox; where the marketing checkbox is also ticked, that marketing consent is extended to SMS marketing. The attendee application applies the same bundling for the terms and processing consents.
Consent is recorded only as a grant. Leaving the marketing checkbox unticked records nothing — no refusal is stored and no consent event is written — and registering again with the box ticked re-grants a marketing consent that was previously withdrawn.
Where an attendee has not granted behavioural-tracking consent, their chat messages, poll votes, reactions, offer clicks and feedback are still written to the live-session database and remain visible to staff on the live dashboard, and their attendance is still recorded against their registration. Only the granular behavioural event rows in the analytics database are suppressed.
On the live watch page the cookie banner and the floating cookie-settings button are suppressed, on the basis that attendees have already been presented with the consent choices at registration. A visitor who opens a watch page directly is therefore not shown a cookie prompt on that page and cannot change or withdraw cookie preferences from it; the scripts classified as strictly necessary, including the Meta and TikTok pixels, still load.
Simulated live attendee count. Where an organisation enables the feature, the attendee count displayed to attendees during a live session is not the true concurrent count: it is computed from a configurable base value plus the real count multiplied by a configurable factor, with a small random variation applied on each reconciliation. Staff see the true count; attendees see the computed figure.
GAP-CONSENT-04 · CODE — KNOWN GAP, REMEDIATION PENDING
This Annex previously asserted privacy as the default, easy consent withdrawal and the absence of dark patterns. Consent to the terms, to the processing of personal data and to SMS notifications is bundled behind a single checkbox or inferred from the presence of a telephone number rather than collected per purpose; withdrawal is unavailable on the live watch page, where the consent controls are removed from the page; and the audience figure shown to attendees may be a computed value rather than the real count. This divergence is recorded on the compliance remediation register and is under review.
Advertising pixels and the cookie banner.
The Meta Pixel and the TikTok Pixel are classified as strictly necessary scripts and are therefore loaded on every page view, before and irrespective of the visitor's cookie-banner decision. Each sends a single page view to Meta and to TikTok respectively at that point, so both platforms receive the visitor's IP address, user agent and page URL before any consent is given. Both are loaded in a consent-withheld state — fbq('consent','revoke') for Meta and ttq.holdConsent() for TikTok — which is intended to prevent the identifying advertising cookies (_fbp, _fbc, _ttp, _ttclid) from being written until the visitor accepts the advertising category, at which point the consent state is flipped to granted. The absence of a cookie is the basis on which these scripts are currently classified as necessary; it is not a determination that the pre-consent load is permitted under Article 5(3) of the ePrivacy Directive, and the classification is under review.
GAP-CONSENT-01 · CODE — KNOWN GAP, REMEDIATION PENDING
This document previously stated that the Meta and TikTok pixels load only where the attendee accepts advertising cookies. Both pixels are in fact classified as necessary and fire a page view before any consent decision, in a configuration intended to be cookie-less until advertising consent is granted. This divergence is recorded on the compliance remediation register; the classification is under review.
Privacy by Default:
- New organizations: contacts retained for the duration of the business relationship (no automatic time-based deletion); behavioural events retained indefinitely, since no retention policy can presently be configured through the product — see §2.6
- New events: Marketing emails off by default (customers enable if needed)
- New staff users: a role is chosen explicitly at account creation; there is no read-only default — see §1.2.1
2.8 Documentation and Compliance
Maintained Documentation:
- This Security Measures document (updated annually)
- Data Processing Agreement (updated per GDPR amendments)
- Record of Processing Activities (ROPA) (updated on feature releases)
- Data Protection Impact Assessment (DPIA) (reviewed annually)
- Data Breach Response Plan (quarterly testing committed; no exercise recorded — see §2.5)
- Employee training records — not maintained; no training programme has been established (see §2.1)
- Vendor DPAs and certifications (stored in legal docs folder) — not complete; see §2.4
Maintenance status. This Annex was last substantively revised before a series of material platform changes, including the introduction of the four-role permission model, changes to the public rate limits, the simulated live attendee count and the app store review demo account; the corrections in the present revision bring it back into line with the platform as deployed. The annual and quarterly cadences listed above are commitments rather than evidenced practice: no dated record of an annual security review, a quarterly tabletop exercise or a quarterly breach-plan test is held with the legal documentation, so none can be produced as audit evidence.
GAP-GOV-06 · PROCESS — KNOWN GAP, REMEDIATION PENDING
This Annex previously presented its own maintenance cadence — annual revision of this document, annual review of the impact assessment, quarterly testing of the breach response plan and maintenance of training and vendor records — as established practice. This document went unrevised across a substantial period of material platform change, and no dated record exists for any of those recurring exercises. This divergence is recorded on the compliance remediation register and is under review.
Compliance Audits:
- Annual internal audit (CTO reviews all security measures)
- External audit (ISO 27001 or SOC 2) planned for [2026]
- Customer audits (on request, per DPA Section 11)
3. Physical Security (Data Centers)
[PLATFORM PROVIDER] does not operate physical data centers. All infrastructure is cloud-hosted:
Railway (EU Region)
- SOC 2 Type II certified
- Physical security: Google Cloud Platform data centers (ISO 27001, biometric access, 24/7 surveillance)
- Location: EU (germany-west or similar)
Google Cloud / Firebase
- ISO 27001, SOC 2, SOC 3 certified
- Physical security: Multi-layered access controls, mantrap entrances, security personnel, video surveillance
- Location: europe-west3 (Frankfurt) for Cloud Functions, europe-west1 for the Realtime Database, EU multi-region for Firestore. ⚠️ The Cloud Storage bucket location is not evidenced in [PLATFORM PROVIDER]'s records and must be confirmed against the project configuration
NewsmanApp SRL (Email Provider)
- Romania-based (EU)
- Physical security: [Request details from Newsman]
[PLATFORM PROVIDER] Office (Development):
- No production data stored on developer laptops (access via SSH/HTTPS only)
- Full disk encryption required (BitLocker on Windows, FileVault on Mac)
- Laptops locked when unattended (auto-lock after 5 min)
- Visitor sign-in log
4. Subprocessor Security
[PLATFORM PROVIDER] engages eleven sub-processors, listed in Annex III.
All sub-processors listed in Annex III are required to implement equivalent security measures:
- Encryption in transit and at rest
- Access controls (MFA, RBAC)
- Regular security audits (ISO 27001 or SOC 2)
- Breach notification within 24-48 hours
- Data deletion upon termination
Status. These requirements are the standard [PLATFORM PROVIDER] applies when engaging a sub-processor; they are not evidenced for every sub-processor today. A data processing agreement is not on file for each, and for two of them — the AI model provider and the transactional messaging provider — processing began before any agreement was executed and before a transfer mechanism was recorded. See §2.4 and Annex III.
Verification: [PLATFORM PROVIDER] reviews sub-processor security documentation annually (request SOC 2 reports, security white papers).
5. Continuous Improvement
Annual Security Review:
- CTO conducts review every January
- Assess new threats (OWASP Top 10 updates, CVEs in dependencies)
- Update security measures as needed
- Budget allocation for security improvements
Post-Incident Reviews:
- After every Security Incident (even minor), conduct root cause analysis
- Update security measures to prevent recurrence
- Share lessons learned with engineering team (anonymized)
Regulatory Monitoring:
- Track GDPR guidance updates from EDPB (European Data Protection Board)
- Track supervisory authority decisions (especially Romanian ANSPDCP)
- Update measures to align with new interpretations
6. Customer-Specific Measures (Upon Request)
The following enhanced measures are available upon Customer request (may incur additional fees):
- Customer-Managed Encryption Keys (CMEK): Customer controls encryption keys for Firestore data (requires Google Cloud KMS setup)
- Dedicated Database Instance: Customer's data isolated in separate PostgreSQL instance (not shared multi-tenant)
- Custom Retention Policies: per-organisation retention periods for the supported data types, within a range of 30 to 3,650 days. Not currently operable: as set out in §2.6, no retention policy can be saved through the product, so this measure cannot be delivered until that is corrected
- IP Whitelisting: Restrict dashboard access to Customer's office IPs
- SAML SSO: Replace Firebase Auth with Customer's identity provider (Okta, Azure AD)
- Dedicated Support: 24/7 phone support for Security Incidents
Document Control
Version: 1.0 (DRAFT) Last Reviewed: [DATE] Next Review: [DATE + 1 year] Owner: CTO, [PLATFORM PROVIDER] Approved By: [Legal Team, DPO]
Review Status: ⚠️ REQUIRES LEGAL REVIEW — This is a draft for lawyer consultation
End of Annex II