feat(stellar-wave): GDPR export, account deletion, fraud geo/fingerprint/velocity/impossible-travel, i18n - #1010
Merged
Conversation
…ity/impossible-travel, and i18n error messages Adds the self-service data export endpoint (issue MettaChain#959), an account-deletion workflow with retention, audit log and legal-hold override (issue MettaChain#960), and IP geolocation, device fingerprinting, velocity checks and impossible-travel alerts in the login pipeline (issue MettaChain#961). Localises ValidationPipe and exception-filter messages via user preference / Accept-Language with English and Spanish catalogues (issue MettaChain#964). Mirrors the existing module patterns and stays inside NestJS conventions. The new migration is purely additive, so scripts/validate-migrations.ts still passes.
|
@walexjnr Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits. You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀 |
…irectly The unit spec for performScheduledDeletion destructure an identifier that buildHarness does not return, so the call/expectation threw undefined is not a function. Asserting on prisma.user.delete, which is the jest.fn the harness already wires, is the smaller change and keeps the harness return shape minimal.
The Stellar Wave branch (MettaChain#959 MettaChain#960 MettaChain#961 MettaChain#964) had inadvertently removed five top-level models and their supporting enums that were delivered on earlier issues (MettaChain#955 Support Tickets, MettaChain#957 Property Tours, MettaChain#958 Webhooks). This broke prisma generate with eight type-resolution validation errors in CI (Type Webhook, TourRequest, AgentAvailability, SupportTicket, SupportTicketNote). Restores the verbatim content of those models + enums from origin/main (append-only edit, no destructive change) so that prisma generate succeeds and the test + benchmark jobs can progress past the schema generation step. The additive migration in prisma/migrations/20260801000000_add_security_compliance_features/ is unchanged.
…e controllers - src/fraud/fraud.service.spec.ts: register GeoLocationService and DeviceFingerprintService in the TestingModule. The FraudService constructor gained these in MettaChain#961 fraud-context work, so the suite was hanging on module compile when Nest could not resolve index [4]/[5]. - test/e2e/users-profile.e2e.spec.ts: register AccountDeletionService and DataExportService in the TestingModule. UsersController picked up these deps in MettaChain#959 / MettaChain#960, and the e2e spec crashed in beforeAll because the TestingModule could no longer resolve the controller's constructor (account-deletion at index [2], data-export at [3]). Both specs now pass when jest is invoked with the same module list the CI test job uses. No source code, schema, or migration changes; this is a test-only fixup.
Contributor
|
@walexjnr Thanks for contributing. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Implements the four Stellar Wave issues assigned to me, behind a single feature branch so the maintainers can review them together.
Closes Implement GDPR-compliant user data export endpoint #959 — GDPR-compliant personal data export.
src/users/data-export.service.tsbundles every user-owned record (profile + preferences, activity logs, login history, search history + analytics, fraud alerts, sessions, properties, transactions, documents, notifications, saved filters, password history, digest preference, etc.) into a single schema-versioned JSON document, then compresses it witharchiverintopropchain-data-export-<job>.zip. Theexport_jobsrow is updated to COMPLETED and a download-ready email is sent.POST /users/me/request-exportandGET /users/me/exports/:jobId/stream(returns aStreamableFilefor Nest's response pipeline).Closes Add user account deletion workflow with configurable retention periods #960 — Account deletion workflow with retention + legal-hold override + audit log.
src/users/account-deletion.service.tsexposesrequestDeletion,cancelDeletion,performScheduledDeletion. Retention defaults to 30 days, clamped to the configurable 7–90 range viaACCOUNT_DELETION_RETENTION_DAYS. Legal-hold users are blocked immediately and the attempt is written to the newaccount_deletion_audittable. Successful deletes also write aPERFORMEDaudit entry.src/users/scheduled-deletion.service.tsnow delegates toaccountDeletionService.performScheduledDeletion()so the existing daily cron at 02:00 stays the entry point.legalHold,deletionReasononUserand a dedicatedAccountDeletionAudittable back the auditability requirement.POST /users/me/request-deletionandPOST /users/me/cancel-deletion. AdminPOST /users/delete-scheduledis preserved and now routes through the same service.Closes Enhance fraud detection with IP geolocation and device fingerprinting #961 — Fraud detection enhancements: IP geolocation + device fingerprinting + velocity + impossible-travel.
src/fraud/geo-location.service.ts— extracts the originating IP fromx-forwarded-for/request.ipand maps a hard-coded set of common IPv4 prefixes to ISO country codes + cities. No external dependency, so it works offline and in unit tests.src/fraud/device-fingerprint.service.ts— stable SHA-256 over (user-agent,accept-language,ip-address) plus a parsedbrowserFamily/osFamily/isMobile/isBotsummary.FraudServicegainsrecordLoginContext,evaluateVelocity,evaluateImpossibleTravelandevaluateDeviceFingerprint.FraudPatternenum is extended withVELOCITY_EXCEEDED,IMPOSSIBLE_TRAVELandDEVICE_FINGERPRINT_MISMATCH(purely additive migration, no DROP / RENAME / SET NOT NULL).Sessiontable gainsdeviceFingerprint,geoCountryCodeandgeoCitycolumns so context is persisted alongside the session row.AuthService.login()callsfraudService.recordLoginContext(user.id, { ipAddress, userAgent })after the existingevaluateSuccessfulLoginpass, so the new evaluations piggyback on every successful authentication.Closes Add localized error messages with i18n support for API responses #964 — Localized error messages with i18n.
src/i18n/module:I18nServicesynchronously loadsen.jsonandes.jsoncatalogues at module init, parses Accept-Language headers (RFC 7231, with quality factors), and exposest(key, lang, params)+translate(key, { userPreference, acceptLanguageHeader })API. Resolution order is user preference → header → English default. Missing keys fall back to English silently so translations can ship incrementally.HttpExceptionFilter,PrismaExceptionFilterandAllExceptionsFilterare updated to translate every error message and surface alanguagefield on the response JSON.main.tsadds aValidationPipeexceptionFactorythat pipes class-validator messages through the sameI18nService.APP_FILTERproviders inAppModulesoI18nServiceis correctly injected via Nest Dependency Injection (the existingapp.useGlobalFilters(...)had to be removed to avoid double-registration).Migration
prisma/migrations/20260801000000_add_security_compliance_features/migration.sql:ALTER TABLE "users" ADD COLUMN "deletion_reason" TEXT,ADD COLUMN "legal_hold" BOOLEAN NOT NULL DEFAULT FALSE(+ index)CREATE TABLE "account_deletion_audit" (...)(+ indexes)ALTER TABLE "sessions" ADD COLUMN "device_fingerprint" TEXT, "geo_country_code" TEXT, "geo_city" TEXT(+ indexes)ALTER TYPE "FraudPattern" ADD VALUE 'VELOCITY_EXCEEDED', 'IMPOSSIBLE_TRAVEL', 'DEVICE_FINGERPRINT_MISMATCH'npx ts-node scripts/validate-migrations.tsreports no destructive changes (✅ No destructive changes detected. All migrations are safe.).Testing
account-deletion.service.spec.ts,data-export.service.spec.ts,i18n.service.spec.ts,geo-location.service.spec.ts,device-fingerprint.service.spec.ts. The two strict-lint spec rewrites also exercise the new types and signature changes.npm run lint -- --max-warnings=0is green on the working tree.lint->validate-migrations->test(postgres service) ->build. No new CI surface area.Risks worth flagging during review
AppModuleregisters the three filters asAPP_FILTERproviders. If the production app registers additional filters elsewhere they'll need to be deduplicated by the maintainers.GeoLocationServiceis intentionally a static IPv4 prefix map (offline-friendly). A real-world rollout would swap this for MaxMind or an external API.DataExportServicewrites the archive under/tmp/propchain-data-exportand emails the resulting path. Files there are not garbage-collected today — that's a follow-up.AccountDeletionService.performScheduledDeletionhas a small TOCTOU window for concurrent reactivation; wrappers in a transaction are a sensible follow-up.Closes #959, Closes #960, Closes #961, Closes #964