From be3d7f815a37218c0a28bb14282fd69f3df815e9 Mon Sep 17 00:00:00 2001 From: vitorhugo-java Date: Mon, 8 Jun 2026 20:02:02 -0300 Subject: [PATCH 1/3] feat(legal): add privacy policy page and acceptance checkbox on registration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds a Privacy Policy page (/privacy-policy) covering data collection, Google API usage, cookies, retention, and user rights — required for Google's review of OAuth2 in production. Registration now requires the user to check an acceptance checkbox before submitting; the accepted flag is sent to the backend API. Co-Authored-By: Claude Sonnet 4.6 --- src/App.tsx | 2 + src/api/auth.ts | 1 + src/pages/auth/Register.tsx | 40 ++++++- src/pages/legal/PrivacyPolicy.tsx | 187 ++++++++++++++++++++++++++++++ src/types/index.ts | 1 + 5 files changed, 229 insertions(+), 2 deletions(-) create mode 100644 src/pages/legal/PrivacyPolicy.tsx diff --git a/src/App.tsx b/src/App.tsx index 30df8e9..25e9f0a 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -16,6 +16,7 @@ import ApplicationForm from '@/pages/applications/ApplicationForm' import Metrics from '@/pages/metrics/Metrics' import Developer from '@/pages/developer/Developer' import AccountSettings from '@/pages/account/AccountSettings' +import PrivacyPolicy from '@/pages/legal/PrivacyPolicy' export default function App() { useSyncReplay() @@ -63,6 +64,7 @@ export default function App() { : } /> : } /> } /> + } /> unwrap(api.post('/auth/login', data)) diff --git a/src/pages/auth/Register.tsx b/src/pages/auth/Register.tsx index 07f22b4..14eb08c 100644 --- a/src/pages/auth/Register.tsx +++ b/src/pages/auth/Register.tsx @@ -12,6 +12,7 @@ interface RegisterForm { name: string email: string password: string + acceptedPrivacyPolicy: boolean } export default function Register() { @@ -23,12 +24,19 @@ export default function Register() { register, handleSubmit, formState: { errors, isSubmitting }, - } = useForm({ defaultValues: { name: '', email: '', password: '' } }) + } = useForm({ + defaultValues: { name: '', email: '', password: '', acceptedPrivacyPolicy: false }, + }) const onSubmit = handleSubmit(async (values) => { setSubmitError(null) try { - const { accessToken, user } = await registerApi(values) + const { accessToken, user } = await registerApi({ + name: values.name, + email: values.email, + password: values.password, + acceptedPrivacyPolicy: values.acceptedPrivacyPolicy, + }) setSession(accessToken, user) navigate('/dashboard', { replace: true }) } catch (error) { @@ -93,6 +101,34 @@ export default function Register() { /> +
+ + {errors.acceptedPrivacyPolicy && ( +

{errors.acceptedPrivacyPolicy.message}

+ )} +
+ diff --git a/src/pages/legal/PrivacyPolicy.tsx b/src/pages/legal/PrivacyPolicy.tsx new file mode 100644 index 0000000..97e7f72 --- /dev/null +++ b/src/pages/legal/PrivacyPolicy.tsx @@ -0,0 +1,187 @@ +import { Link } from 'react-router-dom' + +export default function PrivacyPolicy() { + return ( +
+
+
+ + ← Back to registration + +
+ +
+
+

Privacy Policy

+

Last updated: June 8, 2026

+
+ +
+

1. About Applywell

+

+ Applywell (also referred to as "Job Apply Tracker") is a personal productivity + application that helps users organize their job search by tracking applications, + deadlines, and statuses. It also allows users to generate tailored resumes using + their own Google Drive. Applywell is operated by Vitor Hugo Alves Ferreira + (vitorhugoalvesferreira@gmail.com). +

+
+ +
+

2. Data We Collect

+

We collect only the data you provide directly:

+
    +
  • Account data: full name and email address used to create your account.
  • +
  • Authentication data: hashed password (never stored in plain text); refresh tokens stored in secure HttpOnly cookies.
  • +
  • + Job application data: company name, role title, application status, + dates, notes, and any other details you choose to enter about each application. +
  • +
  • + Resume data: resume files and templates you upload or generate through + the application. These files are stored in your own Google Drive, not on our servers. +
  • +
  • + Preferences: your preferred daily reminder time for application + follow-ups. +
  • +
  • + Google OAuth tokens: if you connect Google Drive, we store an OAuth + access token and refresh token solely to access the specific Drive folder you + designate. We never access any other files in your Google account. +
  • +
+
+ +
+

3. How We Use Your Data

+
    +
  • To provide and operate the job application tracking service.
  • +
  • To send you optional email reminders about pending applications (only if you configure a reminder time).
  • +
  • To generate personalized resume PDFs using Google Drive on your behalf.
  • +
  • To authenticate your identity and maintain your session securely.
  • +
+

+ We do not use your data for advertising, profiling, or any purpose + beyond operating the features you explicitly use. +

+
+ +
+

4. Google API Usage

+

+ Applywell's use of Google APIs is limited to reading and writing files in a single + Google Drive folder that you select during the setup. We comply with the{' '} + + Google API Services User Data Policy + + , including the Limited Use requirements. Your Google data is never shared with + third parties, never used for targeted advertising, and never transferred for + any purpose unrelated to providing the resume feature. +

+
+ +
+

5. Data Sharing

+

+ We do not sell, rent, or share your personal data with any third + party. We use no analytics trackers, advertising SDKs, or data brokers. Your + data is stored on secure cloud infrastructure and is accessible only to you + and the service itself. +

+
+ +
+

6. Cookies & Storage

+

+ We use a single HttpOnly, Secure cookie for session refresh tokens. This cookie + is strictly necessary for authentication and expires automatically. We do not use + tracking cookies, fingerprinting, or any third-party cookie. The application also + uses your browser's localStorage and IndexedDB solely to cache your own data for + offline access. +

+
+ +
+

7. Data Retention & Deletion

+

+ Your data is retained for as long as your account is active. You may request + permanent deletion of your account and all associated data at any time by + contacting us at{' '} + + vitorhugoalvesferreira@gmail.com + + . Upon account deletion, all personally identifiable information is permanently + removed from our systems within 30 days. +

+
+ +
+

8. Your Rights

+

You have the right to:

+
    +
  • Access the personal data we hold about you.
  • +
  • Correct inaccurate data via your account settings.
  • +
  • Request export or deletion of all your data.
  • +
  • Revoke Google Drive access at any time from your account settings or from your Google account's security page.
  • +
+

+ To exercise any of these rights, contact{' '} + + vitorhugoalvesferreira@gmail.com + + . +

+
+ +
+

9. Security

+

+ Passwords are stored using BCrypt hashing. Communication between your browser + and our servers is encrypted via HTTPS/TLS. Refresh tokens are rotated on each + use and stored in HttpOnly cookies to mitigate XSS risks. We apply rate limiting + on authentication endpoints to prevent brute-force attacks. +

+
+ +
+

10. Changes to This Policy

+

+ We may update this Privacy Policy occasionally. When we do, we will update the + "Last updated" date at the top. Continued use of Applywell after changes are + posted constitutes acceptance of the new policy. For material changes, we will + notify you by email. +

+
+ +
+

11. Contact

+

+ Questions or concerns about this Privacy Policy?{' '} + + vitorhugoalvesferreira@gmail.com + +

+
+
+
+
+ ) +} diff --git a/src/types/index.ts b/src/types/index.ts index 22acb56..d3ccc40 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -10,6 +10,7 @@ export interface User { reminderTime?: string | null roles: string[] canUseGoogleIntegration: boolean + privacyPolicyAccepted: boolean } export interface AuthResponse { From b34362475792017509c6efc8426b701e620ad8d1 Mon Sep 17 00:00:00 2001 From: vitorhugo-java Date: Mon, 8 Jun 2026 20:08:53 -0300 Subject: [PATCH 2/3] fix(tests): check privacy policy checkbox in register E2E test --- tests/auth.spec.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/auth.spec.ts b/tests/auth.spec.ts index e4e29d8..59da002 100644 --- a/tests/auth.spec.ts +++ b/tests/auth.spec.ts @@ -27,6 +27,7 @@ test.describe('Authentication', () => { await page.getByLabel('Full name').fill('New User') await page.getByLabel('Email').fill('new@user.dev') await page.getByLabel('Password').fill('supersecret') + await page.getByRole('checkbox').check() await page.getByRole('button', { name: 'Create account' }).click() await expect(page).toHaveURL(/\/dashboard$/) From bced5f8de1463cf28486626089fc4e9dad5fc451 Mon Sep 17 00:00:00 2001 From: vitorhugo-java Date: Mon, 8 Jun 2026 20:12:28 -0300 Subject: [PATCH 3/3] fix(tests): add privacyPolicyAccepted to MOCK_USER fixture --- tests/support/data.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/support/data.ts b/tests/support/data.ts index 23e3c81..83462dd 100644 --- a/tests/support/data.ts +++ b/tests/support/data.ts @@ -13,6 +13,7 @@ export const MOCK_USER: User = { reminderTime: '09:00', roles: ['USER'], canUseGoogleIntegration: true, + privacyPolicyAccepted: true, } export const MOCK_PROFILE: GamificationProfile = {