Regulamin i polityka prywatnosci zgodne ze stanem serwisu
Deploy Polska Lokalnie / deploy (push) Successful in 22s

Audyt pokazal rozbieznosci w obie strony: dokumenty opisywaly funkcje,
ktorych nie ma (logowanie Google/Facebook), a kod robil rzeczy, ktorych
dokumenty nie ujawnialy.

Kod:
- zgody marketingowe domyslnie WYLACZONE (byly true dla kazdego nowego
  konta) + skrypt fix-marketing-consents.sql czyszczacy stare wpisy,
- usuniete tlumaczenie przez nieoficjalne API Google - przy zmianie
  jezyka wysylalo do USA tresci stron, w tym wiadomosci i nazwiska,
- osadzone spacery (YouTube, Matterport, Kuula) laduja sie dopiero po
  zgodzie; YouTube w trybie bez ciasteczek; mapy jak dotad,
- usuniecie konta kasuje dane osobowe (AccountErasureService), a nie
  tylko wiersz app_users,
- wygasle tokeny i kody SMS kasowane po 7 dniach (ExpiredTokenCleaner),
- zapisujemy moment akceptacji regulaminu przy rejestracji.

Dokumenty: opisuja realne funkcje, wszystkich odbiorcow danych (OVH,
Autopay, SMTP, SMS, Esri, OpenStreetMap, YouTube/Matterport/Kuula, GUS),
transfery poza EOG, konkretne okresy przechowywania, procedure zgloszen
z DSA, brak profilowania i tabele pamieci przegladarki zamiast fikcyjnych
cookies analitycznych. Zakres NIS2 i DORA opisany zgodnie z prawda.

Uklad stron prawnych jak reszta serwisu: kontener 1760 px, karty,
spis tresci z boku.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-09-23 21:59:15 +02:00
parent a4457df5f8
commit ca5f3ebfc1
19 changed files with 1187 additions and 603 deletions
+35 -1
View File
@@ -1,5 +1,5 @@
import { test, expect, type Page } from '@playwright/test';
import { ROUTES, negotiationPath, ADMIN_CONVERSATION_SLUG, conversationPath, newConversationPath, paymentPath } from '../src/routes';
import { ROUTES, listingPath, negotiationPath, ADMIN_CONVERSATION_SLUG, conversationPath, newConversationPath, paymentPath } from '../src/routes';
// Standard projektu (AGENTS.md): kazdy widok ma wlasny URL obslugiwany przez React Router,
// a nawigacja odbywa sie przez <Link>/<NavLink>. Te testy pilnuja tej zasady.
@@ -655,3 +655,37 @@ test.describe('Alerty cenowe', () => {
await expect(page.locator('.listing-detail-alert')).toHaveText(/Utwórz alert ceny/);
});
});
// RODO: bez zgody nie ladujemy tresci z obcych serwisow, ktore dostalyby adres IP ogladajacego.
test.describe('Prywatnosc', () => {
test('wirtualny spacer laduje sie dopiero po zgodzie', async ({ page }) => {
const externalHosts = new Set<string>();
page.on('request', (request) => {
const host = new URL(request.url()).hostname;
if (!host.includes('localhost') && !host.includes('127.0.0.1')) {
externalHosts.add(host);
}
});
// Szukamy ogloszenia ze spacerem - tylko tam jest co blokowac.
const listings = await page.request.get('/api/listings?offerType=SALE').then((r) => r.json());
let tourListingId: number | null = null;
for (const item of listings) {
const detail = await page.request.get(`/api/listings/${item.id}`).then((r) => r.json());
if (detail.virtualTourUrl) {
tourListingId = item.id;
break;
}
}
if (tourListingId == null) {
test.skip(true, 'Zadne ogloszenie nie ma wirtualnego spaceru');
}
await goto(page, listingPath(tourListingId!));
await expect(page.locator('.listing-detail-tour-consent')).toBeVisible();
await expect(page.locator('.listing-detail-tour-embed iframe')).toHaveCount(0);
expect([...externalHosts].some((host) => host.includes('youtube') || host.includes('kuula') || host.includes('matterport'))).toBe(false);
await page.getByRole('button', { name: /Pokaż wirtualny spacer/ }).click();
await expect(page.locator('.listing-detail-tour-embed iframe')).toHaveCount(1);
});
});