diff --git a/COMPLIANCE_UPDATE_PLAN.md b/COMPLIANCE_UPDATE_PLAN.md new file mode 100644 index 0000000..873c908 --- /dev/null +++ b/COMPLIANCE_UPDATE_PLAN.md @@ -0,0 +1,697 @@ +# PayChecker - Pre-Launch Compliance Update Plan + +**Plan Date:** 2026-02-23 +**Based on:** LEGAL_COMPLIANCE_REPORT.md +**Objective:** Systematically resolve all identified compliance issues before public launch + +--- + +## Phase Overview + +| Phase | Timeline | Focus | Issue Count | Effort | +|-------|----------|-------|-------------|--------| +| Phase 0 | Immediate (Day 1) | Critical Code Bugs | 1 | 1 hour | +| Phase 1 | Week 1 | Legal Documents Overhaul | 12 | 3-5 days | +| Phase 2 | Week 2 | In-App Disclaimer & Consent UX | 8 | 3-4 days | +| Phase 3 | Week 3 | Security Hardening | 7 | 3-4 days | +| Phase 4 | Week 4 | Marketing Audit & Cleanup | 5 | 2-3 days | +| Phase 5 | Week 5-6 | Accessibility & i18n | 6 | 4-5 days | +| Phase 6 | Week 6-8 | External Legal Consultation | 3 | External | +| Phase 7 | Ongoing | Monitoring & Maintenance | Continuous | Weekly | + +--- + +## Phase 0: Immediate Critical Fix (Day 1) + +### P0-1. Fix Super Rate Inconsistency +**File:** `src/store/useScheduleStore.ts` line 293 +**Issue:** `SUPER_RATE = 0.115` (11.5%) conflicts with `AU_SUPER_RATE = 0.12` (12%) in `src/data/taxRates/australia.ts` +**Action:** +``` +1. Remove SUPER_RATE export from useScheduleStore.ts +2. Update ExportModal.tsx to import AU_SUPER_RATE from taxRates/australia.ts +3. Search entire codebase for any other references to 0.115 +4. Add unit test: SUPER_RATE === AU_SUPER_RATE +``` +**Owner:** Developer +**Verification:** Run full test suite + manual check of Export modal + +--- + +## Phase 1: Legal Documents Overhaul (Week 1) + +### P1-1. Privacy Policy Complete Rewrite +**File:** `public/privacy-policy.html` +**Priority:** CRITICAL +**Tasks:** +``` +1. Add operating entity name and ABN (if applicable) +2. Add comprehensive data inventory table: + | Data Category | Data Fields | Purpose | Retention | + |--------------|-------------|---------|-----------| + | Account | Email, password hash, user ID | Auth | Account lifetime + 6mo | + | Profile | Visa type, country, admin flag | Personalization | Account lifetime | + | Employment | Job names, hourly rates, shift times | Core service | Account lifetime | + | Financial | Income estimates, tax calcs, expenses | Core service | Account lifetime | + | Roster Images | Uploaded PDFs/images | AI extraction | Deleted after processing | + | Roster Results | Parsed shift data, OCR output | Service records | 12 months | + | Feedback | Messages, email, replies | Support | 24 months | + | Technical | IP (anonymized), browser, timestamps | Reliability | 90 days | + +3. Add Third-Party Data Processor section: + - Supabase Inc. (USA) - Database, authentication, edge functions + - Google LLC (USA) - Gemini AI for roster OCR, AdSense for advertising + - Vercel Inc. (USA) - Web hosting and CDN + +4. Add Cross-Border Data Transfer section (APP 8) +5. Add Cookie disclosure section +6. Add data retention periods (specific timeframes) +7. Add deletion request process (30-day maximum) +8. Add Notifiable Data Breach notification commitment +9. Add children's privacy section (minimum age: 16) +10. Add GDPR section for EU users +11. Update effective date +``` + +### P1-2. Terms of Service Rewrite +**File:** `public/terms-of-service.html` +**Priority:** CRITICAL +**Tasks:** +``` +1. Add governing law: "Laws of [State], Australia" +2. Add jurisdiction clause +3. Add Australian Consumer Law savings clause: + "Nothing in these Terms excludes, restricts, or modifies any consumer + guarantee, right, or remedy conferred on you by the Australian Consumer Law + that cannot be excluded, restricted, or modified by agreement." +4. Add User Content section: + - Users retain ownership of their data + - Limited license grant to PayChecker for service delivery + - User warranty that uploaded content is authorized +5. Add indemnification clause (user indemnifies for unauthorized uploads) +6. Add age requirement (16+) +7. Add dispute resolution process +8. Add data portability commitment +9. Add service modification notice period (30 days for material changes) +10. Strengthen financial disclaimer prominently in Section 1 +11. Add AI processing disclosure +12. Update effective date +``` + +### P1-3. Create Cookie Policy Page +**File:** `public/cookie-policy.html` (NEW) +**Priority:** HIGH +**Tasks:** +``` +1. Create cookie-policy.html with same styling as other legal pages +2. Document all cookies/storage: + - localStorage: paychecker-storage-v2 (Essential - app state) + - Supabase auth cookies (Essential - authentication) + - Google AdSense cookies (Advertising - non-essential) +3. Explain how to manage/delete cookies +4. Link from Privacy Policy and footer +``` + +### P1-4. Add LICENSE and THIRD_PARTY_LICENSES Files +**Files:** `LICENSE`, `THIRD_PARTY_LICENSES` (NEW) +**Priority:** HIGH +**Tasks:** +``` +1. Run: npx license-checker --summary --production +2. Verify no GPL/copyleft licenses in production dependencies +3. Create LICENSE file (choose appropriate license) +4. Create THIRD_PARTY_LICENSES with all dependency attributions +5. Add ATO data attribution +``` + +### P1-5. Update About Page +**File:** `public/about.html` +**Priority:** MEDIUM +**Tasks:** +``` +1. Add "Data Sources" section with ATO attribution +2. Add link to Cookie Policy +3. Strengthen disclaimer language +4. Add AI technology disclosure +``` + +### P1-6. Update Contact Page +**File:** `public/contact.html` +**Priority:** MEDIUM +**Tasks:** +``` +1. Verify email addresses actually work (set up email hosting) +2. Add data deletion request process +3. Add privacy complaint handling process +4. Add OAIC contact details for unresolved privacy complaints +``` + +### P1-7. Update Sitemap & Footer +**Files:** `public/sitemap.xml`, `src/components/Content/SiteFooterLinks.tsx` +**Priority:** LOW +**Tasks:** +``` +1. Add cookie-policy.html to sitemap +2. Add Cookie Policy link to footer +3. Update footer disclaimer text to be more prominent +``` + +--- + +## Phase 2: In-App Disclaimer & Consent UX (Week 2) + +### P2-1. Cookie Consent Banner Component +**File:** `src/components/CookieConsent/CookieBanner.tsx` (NEW) +**Priority:** CRITICAL +**Tasks:** +``` +1. Create CookieBanner component: + - Show on first visit (check localStorage) + - Categories: Essential (always on) | Advertising (opt-in) + - Accept All / Manage Preferences / Reject Non-Essential + - Save preference to localStorage + - If Advertising rejected, do NOT load AdSense script +2. Move AdSense +``` + +**수정 후 `index.html`:** +```html + +``` + +AdSense 스크립트를 `index.html`에서 제거하고, 쿠키 동의 후 동적으로 로드: + +**새 파일:** `src/utils/adSenseLoader.ts` + +```typescript +let loaded = false; + +export function loadAdSense(): void { + if (loaded) return; + + const script = document.createElement('script'); + script.src = 'https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-4516626856296531'; + script.async = true; + script.crossOrigin = 'anonymous'; + document.head.appendChild(script); + + loaded = true; +} + +export function isAdSenseLoaded(): boolean { + return loaded; +} +``` + +#### Step 2: GoogleAd 컴포넌트에 동의 확인 추가 + +**파일:** `src/components/GoogleAd.tsx` + +```typescript +import { getConsentStatus } from '../utils/cookieConsent'; + +export const GoogleAd: React.FC = (props) => { + const hasAdConsent = getConsentStatus('advertising'); + + if (!hasAdConsent) { + return null; // 동의 없으면 광고 표시하지 않음 + } + + // ... 기존 광고 렌더링 로직 +}; +``` + +#### Step 3: Google의 EU Consent Mode 구현 + +```typescript +// src/utils/googleConsent.ts +export function initGoogleConsentMode() { + window.gtag?.('consent', 'default', { + 'ad_storage': 'denied', + 'ad_user_data': 'denied', + 'ad_personalization': 'denied', + 'analytics_storage': 'denied', + }); +} + +export function updateGoogleConsent(granted: boolean) { + window.gtag?.('consent', 'update', { + 'ad_storage': granted ? 'granted' : 'denied', + 'ad_user_data': granted ? 'granted' : 'denied', + 'ad_personalization': granted ? 'granted' : 'denied', + }); +} +``` + +#### Step 4: 금융 서비스 콘텐츠 정책 검토 + +Google AdSense의 "금융 서비스" 관련 제한 사항: +- 세금 계산이 표시되는 페이지에서 광고가 "금융 상품" 광고로 오인될 수 있는지 검토 +- 필요 시 특정 페이지에서 광고 표시 제한 + +### 검증 방법 +1. 쿠키 동의 전에 AdSense 스크립트가 로드되지 않는지 확인 +2. 동의 후에만 광고가 표시되는지 확인 +3. Google AdSense 대시보드에서 정책 위반 경고 없는지 확인 +4. EU 위치에서 접속 시 Consent Mode가 작동하는지 확인 + +### 예상 소요 시간: 2-3일 (CRITICAL-7과 병행) + +### 위험도: 중간 (AdSense 계정 정지 가능) + +--- + +## CRITICAL-6. 보안 감사 미실시 + +### 현재 상태 + +**현재 보안 조치:** +- CI 파이프라인: `npm audit --omit=dev --audit-level=high` +- `dangerouslySetInnerHTML` 사용 금지 검사: `npm run check:no-danger` +- Supabase RLS(Row Level Security): 모든 테이블에 활성화 +- CORS: 허용 도메인 목록 기반 (but 와일드카드 문제 있음) +- 인증: Supabase Auth + Bearer Token + +**미실시 항목:** + +| 보안 영역 | 현재 상태 | 리스크 | +|-----------|-----------|--------| +| OWASP Top 10 검토 | 미실시 | XSS, Injection, SSRF 등 | +| 침투 테스트 | 미실시 | Edge Function 취약점 | +| CSP (Content Security Policy) | 미설정 | XSS 방어 없음 | +| HSTS | 미설정 (Vercel 기본값에 의존) | 다운그레이드 공격 | +| CORS 와일드카드 | `hostname.includes('paychecker')` 패턴 | 유사 도메인 위조 가능 | +| RLS 감사 | 미실시 | 권한 상승 가능성 | +| Health endpoint | 설정 정보 노출 | 정찰 공격 지원 | +| 의존성 취약점 | CI 기본 감사만 | 중간 심각도 이하 누락 | + +### 수정 방안 + +#### Phase 1: 즉시 조치 (코드 변경) + +##### 1-A. Content Security Policy 헤더 설정 + +**파일:** `vercel.json` (NEW) + +```json +{ + "headers": [ + { + "source": "/(.*)", + "headers": [ + { + "key": "Content-Security-Policy", + "value": "default-src 'self'; script-src 'self' https://pagead2.googlesyndication.com https://*.google.com https://*.gstatic.com https://*.googlesyndication.com 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob: https://*.supabase.co https://*.google.com https://*.googleusercontent.com https://*.googlesyndication.com; connect-src 'self' https://*.supabase.co wss://*.supabase.co https://pagead2.googlesyndication.com https://generativelanguage.googleapis.com; frame-src https://googleads.g.doubleclick.net https://tpc.googlesyndication.com https://*.google.com; font-src 'self' data:;" + }, + { + "key": "Strict-Transport-Security", + "value": "max-age=63072000; includeSubDomains; preload" + }, + { + "key": "X-Content-Type-Options", + "value": "nosniff" + }, + { + "key": "X-Frame-Options", + "value": "DENY" + }, + { + "key": "Referrer-Policy", + "value": "strict-origin-when-cross-origin" + }, + { + "key": "Permissions-Policy", + "value": "camera=(), microphone=(), geolocation=(), interest-cohort=()" + } + ] + } + ] +} +``` + +##### 1-B. CORS 정책 강화 + +**파일:** `supabase/functions/process-roster/index.ts` + +```diff + function isAllowedOrigin(origin: string): boolean { + if (getAllowedOrigins().includes(origin)) return true; +- // Allow Vercel preview deployments +- try { +- const url = new URL(origin); +- if (url.hostname.endsWith('.vercel.app') && url.hostname.includes('paychecker')) return true; +- } catch { /* ignore invalid URLs */ } + return false; + } +``` + +와일드카드 매칭 제거. preview deployment URL은 `ALLOWED_ORIGINS` 환경변수를 통해서만 허용. + +##### 1-C. Health endpoint 정보 노출 축소 + +**파일:** `supabase/functions/process-roster/index.ts` + +```diff + if (req.method === 'GET') { +- const supabaseUrl = Deno.env.get('SUPABASE_URL'); +- const hasServiceKey = Boolean( +- Deno.env.get('SUPABASE_SERVICE_ROLE_KEY') || Deno.env.get('SERVICE_ROLE_KEY') +- ); + return json(200, { + success: true, + status: 'healthy', + timestamp: new Date().toISOString(), +- config: { +- hasSupabaseUrl: Boolean(supabaseUrl), +- hasServiceRoleKey: hasServiceKey, +- hasGeminiKey: Boolean(Deno.env.get('GEMINI_API_KEY')), +- }, + }); + } +``` + +프로덕션에서 서비스 설정 정보를 외부에 노출하지 않습니다. + +##### 1-D. RLS 보안 강화 - Admin 권한 상승 방지 + +```sql +-- is_admin 필드를 사용자가 직접 변경할 수 없도록 방지 +-- 기존 UPDATE 정책에 추가 제약 조건 +CREATE POLICY "prevent_admin_self_escalation" ON profiles +FOR UPDATE TO authenticated +USING (id = auth.uid()) +WITH CHECK ( + CASE + WHEN is_admin IS DISTINCT FROM (SELECT p.is_admin FROM profiles p WHERE p.id = auth.uid()) + THEN false -- is_admin 변경 시도 시 차단 + ELSE true + END +); +``` + +#### Phase 2: 체계적 보안 감사 (1-2주) + +##### 2-A. OWASP Top 10 체크리스트 + +| # | OWASP 항목 | PayChecker 해당 여부 | 검토 항목 | +|---|-----------|---------------------|-----------| +| A01 | Broken Access Control | ✅ | RLS 정책 전체 검증, userId 필터 bypas 가능성 | +| A02 | Cryptographic Failures | ⚠️ | Supabase 기본 암호화, 민감 데이터 암호화 여부 | +| A03 | Injection | ✅ | Edge Function 입력 검증, SQL injection (Supabase가 방어) | +| A04 | Insecure Design | ⚠️ | 비밀번호 정책, 세션 관리 (Supabase Auth) | +| A05 | Security Misconfiguration | ✅ | CSP, CORS, 에러 메시지, 디버그 정보 | +| A06 | Vulnerable Components | ✅ | npm audit, 의존성 취약점 | +| A07 | Auth Failures | ⚠️ | 토큰 관리, 세션 타임아웃 | +| A08 | Software Integrity | ⚠️ | CI/CD 파이프라인 보안, SRI | +| A09 | Security Logging | ⚠️ | Edge Function 로깅, 이상 탐지 | +| A10 | Server-Side Request Forgery | ✅ | Gemini API 호출 (Base64 이미지만 허용) | + +##### 2-B. 의존성 보안 감사 강화 + +```bash +# 현재 (CI에서 실행) +npm audit --omit=dev --audit-level=high + +# 강화 (추가 감사) +npm audit --audit-level=moderate +npx better-npm-audit audit +npx license-checker --failOn 'GPL;AGPL' +``` + +##### 2-C. RLS 자동화 테스트 + +```typescript +// supabase/tests/rls-audit.test.ts +describe('RLS Policy Audit', () => { + it('User A cannot read User B shifts', async () => { + // ... + }); + it('User cannot set is_admin to true', async () => { + // ... + }); + it('Non-admin cannot access admin feedback', async () => { + // ... + }); +}); +``` + +#### Phase 3: 외부 침투 테스트 (선택, 권장) + +- **범위:** Supabase Edge Function, Auth flow, RLS policies +- **예상 비용:** AUD $3,000 - $10,000 +- **시기:** Phase 1 & 2 완료 후 + +### 검증 방법 +1. `vercel.json`의 보안 헤더가 응답에 포함되는지 확인 (curl -I) +2. CORS 와일드카드가 제거되었는지 확인 +3. Health endpoint에서 설정 정보가 노출되지 않는지 확인 +4. `npm audit` 결과에 high/critical 취약점 없는지 확인 + +### 예상 소요 시간 +- Phase 1 (즉시 조치): 2-3일 +- Phase 2 (체계적 감사): 1-2주 +- Phase 3 (침투 테스트): 외부 의뢰 2-4주 + +### 위험도: 높음 (데이터 유출 시 NDB 의무 발생) + +--- + +## CRITICAL-7. Cookie 동의 미구현 + +### 현재 상태 + +**사용 중인 쿠키/스토리지:** + +| 유형 | 키/이름 | 목적 | 분류 | 동의 필요 | +|------|---------|------|------|-----------| +| localStorage | `paychecker-storage-v2` | Zustand 상태 유지 (앱 핵심 기능) | 필수 (Essential) | 아니오 | +| Supabase Auth | `sb-*-auth-token` | 인증 세션 관리 | 필수 (Essential) | 아니오 | +| Google AdSense | 다수의 추적 쿠키 | 개인화 광고 | 광고 (Advertising) | **예** | +| Google AdSense | 행동 추적 | 광고 타겟팅 | 광고 (Advertising) | **예** | + +**법적 요구사항:** +- **호주:** Cookie 동의가 명시적으로 법률 요구사항은 아니나, Privacy Act의 투명성 원칙에 의해 고지 필요 +- **EU (GDPR/ePrivacy):** Working Holiday Maker 사용자가 EU 출신일 수 있으므로 명시적 동의 필요 +- **Google AdSense 정책:** EU User Consent Policy에 의해 CMP 필수 + +### 수정 방안 + +#### Step 1: Cookie Consent 상태 관리 유틸리티 + +**파일:** `src/utils/cookieConsent.ts` (NEW) + +```typescript +export type CookieCategory = 'essential' | 'advertising'; + +interface ConsentState { + essential: boolean; // 항상 true + advertising: boolean; // 사용자 선택 + timestamp: string; // 동의 시점 + version: string; // 동의 정책 버전 +} + +const CONSENT_KEY = 'paychecker-cookie-consent'; +const CONSENT_VERSION = '1.0'; + +export function getConsentState(): ConsentState | null { + try { + const stored = localStorage.getItem(CONSENT_KEY); + if (!stored) return null; + return JSON.parse(stored); + } catch { + return null; + } +} + +export function setConsentState(advertising: boolean): void { + const state: ConsentState = { + essential: true, + advertising, + timestamp: new Date().toISOString(), + version: CONSENT_VERSION, + }; + localStorage.setItem(CONSENT_KEY, JSON.stringify(state)); +} + +export function getConsentStatus(category: CookieCategory): boolean { + if (category === 'essential') return true; + const state = getConsentState(); + return state?.[category] ?? false; +} + +export function hasGivenConsent(): boolean { + return getConsentState() !== null; +} + +export function resetConsent(): void { + localStorage.removeItem(CONSENT_KEY); +} +``` + +#### Step 2: Cookie Consent Banner 컴포넌트 + +**파일:** `src/components/CookieConsent/CookieBanner.tsx` (NEW) + +기능: +- 첫 방문 시 하단에 배너 표시 +- "Accept All" / "Essential Only" / "Manage Preferences" 버튼 +- "Essential Only" 선택 시 AdSense 로드하지 않음 +- 동의 상태를 localStorage에 저장 +- Manage Preferences에서 카테고리별 토글 + +``` +┌────────────────────────────────────────────────────────────────┐ +│ 🍪 We use cookies │ +│ │ +│ We use essential cookies for the app to function and optional │ +│ cookies for advertising (Google AdSense). │ +│ │ +│ Learn more in our [Cookie Policy] and [Privacy Policy]. │ +│ │ +│ [Essential Only] [Accept All] [Manage Preferences] │ +└────────────────────────────────────────────────────────────────┘ +``` + +#### Step 3: App.tsx에 통합 + +**파일:** `src/App.tsx` + +```typescript +import { CookieBanner } from './components/CookieConsent/CookieBanner'; +import { hasGivenConsent, getConsentStatus } from './utils/cookieConsent'; +import { loadAdSense } from './utils/adSenseLoader'; + +function App() { + const [showCookieBanner, setShowCookieBanner] = useState(!hasGivenConsent()); + + useEffect(() => { + if (getConsentStatus('advertising')) { + loadAdSense(); + } + }, []); + + const handleConsentChange = () => { + setShowCookieBanner(false); + if (getConsentStatus('advertising')) { + loadAdSense(); + } + }; + + // ... 기존 코드 + + return ( + <> + {/* ... 기존 코드 */} + {showCookieBanner && } + + ); +} +``` + +#### Step 4: index.html에서 AdSense 스크립트 제거 + +**파일:** `index.html` + +```diff +- +``` + +AdSense는 이제 동의 후 동적으로 로드됩니다. + +#### Step 5: GoogleAd 컴포넌트 수정 + +**파일:** `src/components/GoogleAd.tsx` + +```typescript +export const GoogleAd: React.FC = (props) => { + const hasConsent = getConsentStatus('advertising'); + + // 광고 동의가 없으면 렌더링하지 않음 + if (!hasConsent) return null; + + // ... 기존 로직 +}; +``` + +#### Step 6: Cookie Policy 페이지 생성 + +**파일:** `public/cookie-policy.html` (NEW) + +Privacy Policy, Terms of Service와 동일한 스타일로 작성: +- 사용되는 쿠키/스토리지 목록 +- 각 쿠키의 목적, 보존 기간 +- 쿠키 관리 방법 +- 브라우저에서 쿠키 삭제하는 방법 + +#### Step 7: 푸터 및 사이트맵 업데이트 + +**파일:** `src/components/Content/SiteFooterLinks.tsx` +```diff + const FOOTER_LINKS = [ + { href: '/about.html', label: 'About' }, + { href: '/privacy-policy.html', label: 'Privacy Policy' }, + { href: '/terms-of-service.html', label: 'Terms of Service' }, ++ { href: '/cookie-policy.html', label: 'Cookie Policy' }, + { href: '/contact.html', label: 'Contact' }, + ]; +``` + +**파일:** `public/sitemap.xml` +```diff ++ https://paychecker-six.vercel.app/cookie-policy.html +``` + +### 검증 방법 +1. 첫 방문 시 쿠키 배너가 표시되는지 확인 +2. "Essential Only" 선택 시 AdSense가 로드되지 않는지 확인 +3. "Accept All" 선택 시 광고가 정상 표시되는지 확인 +4. 동의 후 새로고침 시 배너가 다시 나타나지 않는지 확인 +5. 브라우저 개발자 도구에서 쿠키 확인 +6. Cookie Policy 페이지 접근 가능 확인 + +### 예상 소요 시간: 3-4일 + +### 위험도: 중간 (AdSense 정책 위반 가능) + +--- + +## CRITICAL-8. 준거법 미지정 + +### 현재 상태 + +**파일:** `public/terms-of-service.html` + +현재 Terms of Service에 다음이 **누락**되어 있습니다: +- 준거법 (Governing Law) +- 관할 법원 (Jurisdiction) +- 분쟁 해결 절차 (Dispute Resolution) +- 호주 소비자법 (ACL) 저축 조항 + +또한 다음도 누락: +- 사용자 콘텐츠 소유권 조항 +- 배상 조항 (Indemnification) +- 최소 이용 연령 +- AI 처리 고지 +- 서비스 변경 통지 기간 + +### 수정 방안 + +#### Terms of Service에 추가해야 할 핵심 조항 + +##### 1. 준거법 (Governing Law) + +```html +

9. Governing Law

+

+ These Terms are governed by the laws of [New South Wales / Victoria / + Queensland], Australia. Any disputes arising from or relating to these + Terms or the Service will be subject to the exclusive jurisdiction of + the courts of [State], Australia. +

+``` + +**Owner 결정 필요:** 어느 주(State) 법률을 적용할 것인지 + +##### 2. 분쟁 해결 (Dispute Resolution) + +```html +

10. Dispute Resolution

+

+ Before initiating legal proceedings, you agree to attempt to resolve + any dispute informally by contacting us at [email]. If the dispute is + not resolved within 30 days, either party may pursue formal resolution + through the courts of [State], Australia. +

+

+ For complaints about the handling of personal information, you may also + contact the Office of the Australian Information Commissioner (OAIC) at + www.oaic.gov.au. +

+``` + +##### 3. 호주 소비자법 (ACL) 저축 조항 + +```html +

11. Australian Consumer Law

+

+ Nothing in these Terms excludes, restricts, or modifies any consumer + guarantee, right, or remedy conferred on you by the Australian Consumer + Law (Schedule 2 of the Competition and Consumer Act 2010) that cannot + be excluded, restricted, or modified by agreement. +

+``` + +**이것은 법적 필수 사항입니다.** 현재 Section 6의 "as is" 면책 조항과 함께, ACL 준수 조항이 없으면 해당 면책이 무효화될 수 있습니다. + +##### 4. 사용자 콘텐츠 소유권 + +```html +

12. User Content

+

You retain all ownership rights to the data you create in PayChecker +(shift records, job configurations, expense records, and other personal data).

+

By using the Service, you grant PayChecker a limited, non-exclusive license +to process your data solely for the purpose of providing the Service to you.

+

When uploading roster images, you represent and warrant that:

+
    +
  • You have the right or authorization to share the document
  • +
  • You understand the image will be processed by third-party AI services
  • +
  • You accept responsibility for any third-party personal information + contained in the uploaded content
  • +
+``` + +##### 5. 배상 조항 (Indemnification) + +```html +

13. Indemnification

+

You agree to indemnify and hold PayChecker harmless from any claims, +damages, or expenses arising from:

+
    +
  • Your use of the Service in violation of these Terms
  • +
  • Content you upload that you do not have the right to share
  • +
  • Reliance on estimates provided by the Service for tax, payroll, + or immigration purposes
  • +
+``` + +##### 6. 재무 면책 조항 강화 (Section 1 수정) + +```html +

1. Service Scope and Financial Disclaimer

+

PayChecker provides roster management and pay-estimation tools for +planning and personal record-keeping purposes only.

+

Important:

+
    +
  • PayChecker is NOT payroll software, a registered + tax agent, financial advice, legal advice, or immigration advice
  • +
  • All monetary values (pay estimates, tax estimates, superannuation) + are approximations only
  • +
  • Tax estimates are based on publicly available ATO data and may not + reflect your actual tax obligations
  • +
  • Always verify all amounts with your employer, official payslips, + and a registered tax agent
  • +
  • PayChecker is not registered with the Tax Practitioners Board
  • +
+``` + +##### 7. 최소 이용 연령 + +```html +

14. Age Requirement

+

You must be at least 16 years old to use PayChecker. By using the +Service, you represent that you meet this age requirement.

+``` + +##### 8. AI 처리 고지 + +```html +

15. AI-Powered Features

+

PayChecker uses artificial intelligence (Google Gemini) to extract +text from uploaded roster images. By using this feature, you acknowledge:

+
    +
  • Images are transmitted to Google's servers for processing
  • +
  • AI extraction may contain errors and must be verified by you
  • +
  • You are responsible for reviewing all AI-extracted data before use
  • +
+``` + +##### 9. 서비스 변경 통지 + +```html +

16. Changes to Terms and Service

+

We may update these Terms from time to time. For material changes, +we will provide at least 30 days' notice via:

+
    +
  • A notice posted on the Service
  • +
  • An update to the effective date on this page
  • +
+

Your continued use after the notice period constitutes acceptance +of the updated Terms.

+``` + +### 전체 Terms of Service 구조 (수정 후) + +``` +1. Service Scope and Financial Disclaimer (강화) +2. Account Responsibilities (기존 유지) +3. Data Accuracy and Verification (기존 유지) +4. Availability and Modifications (기존 유지, 통지 기간 추가) +5. Third-Party Services (기존 유지) +6. Limitation of Liability (기존 유지, ACL 참조 추가) +7. Termination (기존 유지) +8. Contact (기존 유지) +9. Governing Law (NEW) +10. Dispute Resolution (NEW) +11. Australian Consumer Law (NEW - 필수) +12. User Content (NEW) +13. Indemnification (NEW) +14. Age Requirement (NEW) +15. AI-Powered Features (NEW) +16. Changes to Terms and Service (NEW) +``` + +### Owner 결정 필요 사항 +- [ ] 준거법 주(State): NSW / VIC / QLD / 기타 +- [ ] 최소 이용 연령: 16세 vs 13세 +- [ ] 배상 조항의 범위 + +### 검증 방법 +1. Terms of Service에 모든 필수 조항이 포함되었는지 확인 +2. ACL 저축 조항이 Section 6 (Limitation of Liability)와 모순 없는지 확인 +3. 법률 자문가의 검토 (권장) + +### 예상 소요 시간: 2-3일 (법률 검토 별도) + +### 위험도: 높음 (법적 문서이므로 전문가 검토 권장) + +--- + +## 구현 우선순위 및 일정 + +### 우선순위 매트릭스 + +| 순위 | 항목 | 긴급도 | 복잡도 | 소요 시간 | 의존성 | +|------|------|--------|--------|-----------|--------| +| 1 | CRITICAL-1 (Super Rate) | 즉시 | 낮음 | 1시간 | 없음 | +| 2 | CRITICAL-8 (준거법) | 1주차 | 중간 | 2-3일 | Owner 결정 | +| 3 | CRITICAL-2 (Privacy Policy) | 1주차 | 높음 | 3-5일 | Owner 결정 | +| 4 | CRITICAL-3 (해외 전송) | 1주차 | 중간 | 2-3일 | CRITICAL-2와 병행 | +| 5 | CRITICAL-7 (Cookie 동의) | 2주차 | 중간 | 3-4일 | CRITICAL-5와 병행 | +| 6 | CRITICAL-5 (AdSense) | 2주차 | 중간 | 2-3일 | CRITICAL-7 필요 | +| 7 | CRITICAL-4 (세무사법) | 1-2주차 (코드) / 6주차 (법률) | 높음 | 코드 2-3일 + 법률 2-3주 | 법률 자문 | +| 8 | CRITICAL-6 (보안 감사) | 3주차 | 높음 | 1-2주 | CRITICAL-5,7 이후 | + +### 실행 일정 + +``` +Day 1 (즉시): + ✅ CRITICAL-1: Super Rate 수정 (1시간) + +Week 1: + 📝 CRITICAL-8: Terms of Service 재작성 + 📝 CRITICAL-2: Privacy Policy 재작성 + 📝 CRITICAL-3: 해외 전송 고지 (Privacy Policy에 포함) + 📝 CRITICAL-4 단계A: 세금 면책 조항 코드 추가 + +Week 2: + 🔧 CRITICAL-7: Cookie Consent 구현 + 🔧 CRITICAL-5: AdSense 조건부 로드 (CRITICAL-7과 연계) + 📝 CRITICAL-4 단계A: 마케팅 문구 수정 + +Week 3: + 🔒 CRITICAL-6 Phase 1: CSP, CORS, 즉시 보안 조치 + 🔒 CRITICAL-6 Phase 2: OWASP 체크리스트, RLS 감사 + +Week 4-6: + ⚖️ CRITICAL-4 단계B: 세법 전문 변호사 의뢰 + ⚖️ CRITICAL-6 Phase 3: 외부 침투 테스트 (선택) + ⚖️ CRITICAL-2 & 8: 법률 자문가 검토 + +Week 6+: + ⚖️ CRITICAL-4 단계C: 법률 의견에 따른 후속 조치 +``` + +### 총 예상 비용 + +| 항목 | 예상 비용 (AUD) | 필수 여부 | +|------|----------------|-----------| +| 개발자 작업 (3-4주) | 내부 비용 | 필수 | +| 세법 변호사 의견 | $2,000 - $5,000 | 강력 권장 | +| Terms/Privacy 법률 검토 | $1,500 - $3,000 | 권장 | +| 외부 침투 테스트 | $3,000 - $10,000 | 선택 | +| **합계** | **$6,500 - $18,000** | | + +### Launch Gate 기준 + +**다음 항목이 모두 완료되기 전에는 공개 홍보를 시작하지 않습니다:** + +1. ✅ CRITICAL-1 완료 (Super Rate 수정) +2. ✅ CRITICAL-2 완료 (Privacy Policy 재작성) +3. ✅ CRITICAL-3 완료 (해외 전송 고지) +4. ✅ CRITICAL-4 단계A 완료 (면책 조항 추가) +5. ✅ CRITICAL-5 완료 (AdSense 정책 준수) +6. ✅ CRITICAL-6 Phase 1 완료 (CSP, CORS 보안 조치) +7. ✅ CRITICAL-7 완료 (Cookie 동의) +8. ✅ CRITICAL-8 완료 (준거법 지정) +9. ⚖️ CRITICAL-4 단계B 착수 (법률 자문 의뢰) + +**최소 준비 기간: 3-4주** + +--- + +## Owner 결정 요약 + +모든 CRITICAL 항목의 수정을 진행하기 전에 다음 사항에 대한 결정이 필요합니다: + +| # | 결정 사항 | 영향 범위 | 기본 권장안 | +|---|----------|-----------|------------| +| 1 | 운영 주체 (개인/법인) 및 ABN | CRITICAL-2, 3 | 개인 사업자로 시작 | +| 2 | 준거법 적용 주(State) | CRITICAL-8 | NSW (시드니 기반 가정) | +| 3 | 최소 이용 연령 | CRITICAL-2, 8 | 16세 | +| 4 | 한국 시장 진출 여부 | CRITICAL-2, 4 | 초기 런칭 시 제외 | +| 5 | 법률 자문 예산 승인 | CRITICAL-4 | AUD $3,500 - $8,000 | +| 6 | 실제 수신 가능한 이메일 주소 | CRITICAL-2, 3, 8 | 커스텀 도메인 이메일 | +| 7 | 외부 침투 테스트 승인 | CRITICAL-6 | 선택, 예산 여유 시 | +| 8 | 데이터 보존 기간 최종 확정 | CRITICAL-2 | 제안된 기간 승인 | + +--- + +*End of Critical Issues Remediation Plan* diff --git a/LEGAL_COMPLIANCE_REPORT.md b/LEGAL_COMPLIANCE_REPORT.md new file mode 100644 index 0000000..0d2698f --- /dev/null +++ b/LEGAL_COMPLIANCE_REPORT.md @@ -0,0 +1,891 @@ +# PayChecker - Public Launch Legal Compliance Report + +**Report Date:** 2026-02-23 +**Prepared by:** Internal Compliance Review +**Project:** PayChecker (paychecker-six.vercel.app) +**Status:** PRE-LAUNCH REVIEW + +--- + +## Executive Summary + +PayChecker is a web-based roster management and pay estimation tool targeting Australian shift workers (casual, working holiday visa, student visa holders). Before public launch and promotional campaigns, this report identifies **every legal and regulatory obligation** that must be satisfied, categorized by risk severity. + +### Risk Summary Dashboard + +| Category | Critical | High | Medium | Low | Total | +|----------|----------|------|--------|-----|-------| +| Privacy & Data Protection | 3 | 4 | 2 | 1 | 10 | +| Financial Disclaimers & Regulation | 2 | 3 | 2 | 0 | 7 | +| Terms of Service & Contracts | 1 | 3 | 2 | 0 | 6 | +| Advertising & Marketing | 1 | 2 | 3 | 1 | 7 | +| Accessibility & Anti-Discrimination | 0 | 2 | 2 | 1 | 5 | +| Intellectual Property | 0 | 1 | 2 | 1 | 4 | +| Platform & Technical Compliance | 1 | 2 | 3 | 0 | 6 | +| International (Korea/Visa Holders) | 0 | 2 | 2 | 0 | 4 | +| **Total** | **8** | **19** | **18** | **4** | **49** | + +--- + +## 1. PRIVACY & DATA PROTECTION + +### 1.1 Australian Privacy Act 1988 Compliance + +#### 1.1.1 [CRITICAL] Australian Privacy Principles (APPs) - APP Entity Classification + +**Current State:** The Privacy Policy (effective 2026-02-19) exists but is vaguely drafted. + +**Issues Identified:** +- No explicit statement of which entity operates PayChecker (individual, company, or partnership) +- If annual turnover exceeds AUD $3 million, you MUST comply fully with the APPs +- Even below the threshold, handling **Tax File Number (TFN) equivalent data** (income/tax estimation data) may trigger APP obligations +- The Privacy Act's Small Business Exemption does NOT apply if you collect sensitive information or provide a service under a government contract + +**Required Actions:** +1. Determine and declare the operating legal entity +2. Conduct a **Privacy Impact Assessment (PIA)** before launch +3. Register with the **Office of the Australian Information Commissioner (OAIC)** if required +4. Explicitly list all 13 APPs in your compliance framework + +#### 1.1.2 [CRITICAL] APP 1 - Collection Transparency + +**Current State:** The Privacy Policy lists categories of data collected (account identifiers, schedule data, uploads, technical logs) but lacks specificity. + +**Issues Identified:** +- No mention of the **specific data fields** collected (email, password hash, visa type, employer names, hourly rates, income amounts) +- No explicit consent mechanism at sign-up for data collection +- **Visa type** data is potentially **sensitive information** under the Privacy Act (relating to racial or ethnic origin) +- No disclosure that **roster images** are sent to Google Gemini API (a US-based third-party AI service) +- No mention of **Supabase** as the data processor or its data location + +**Required Actions:** +1. Add a comprehensive data inventory table to the Privacy Policy +2. Implement explicit opt-in consent at sign-up (not just "by using the service you agree") +3. Disclose ALL third-party data processors by name: + - **Supabase** (database, auth) - AWS infrastructure + - **Google Gemini API** (AI roster extraction) - US-based + - **Google AdSense** (advertising) - US-based + - **Vercel** (hosting) - US-based +4. State the specific jurisdiction(s) where data is stored + +#### 1.1.3 [CRITICAL] Cross-Border Data Transfer (APP 8) + +**Current State:** No disclosure of overseas data transfer. + +**Issues Identified:** +- User data flows to: + - **Supabase** (likely US/AWS) for storage + - **Google Gemini** (US) for OCR/AI processing of roster images + - **Google AdSense** (US) for ad personalization + - **Vercel** (US) for hosting +- APP 8 requires the entity to take reasonable steps to ensure overseas recipients comply with APPs, OR obtain explicit informed consent + +**Required Actions:** +1. Add a "Cross-Border Data Transfers" section to Privacy Policy +2. List each overseas recipient, their country, and what data they receive +3. Implement either: + - Contractual protections (Data Processing Agreements) with each provider, OR + - Explicit informed consent from users for overseas transfers + +#### 1.1.4 [HIGH] Consent for AI Processing of Roster Images + +**Current State:** Users upload roster images which are sent to Google Gemini API. No explicit disclosure. + +**Issues Identified:** +- Roster images may contain **other employees' personal information** (names, shifts, roles) +- Users may upload images containing data they don't have rights to share +- Google Gemini's data processing terms may allow training on submitted data +- No consent from the **third parties** whose data appears in roster images + +**Required Actions:** +1. Add a clear warning before roster upload explaining: + - The image will be processed by Google's AI + - Other people's data may be visible in the image + - Users must have authority to share workplace documents +2. Review Google Gemini API terms for data retention/training clauses +3. Consider implementing PII redaction before sending to Gemini +4. Add to Terms of Service: user responsibility for uploaded content + +#### 1.1.5 [HIGH] Data Retention & Deletion (APP 11) + +**Current State:** Privacy Policy says "We retain data as needed" with no specific timeframes. + +**Issues Identified:** +- No defined retention periods for any data category +- No automated data cleanup processes +- Roster scan results (`roster_scans` table) store full parsed results indefinitely +- No clear "right to deletion" process documented +- Feedback data includes user email addresses stored in plaintext + +**Required Actions:** +1. Define and publish specific retention periods: + - Account data: Duration of account + X months + - Shift data: Configurable by user, maximum Y years + - Roster scan images: Delete after processing (do NOT store) + - Roster scan metadata: 12 months + - Feedback: 24 months + - Technical logs: 90 days +2. Implement automated data purge jobs +3. Create a formal account deletion endpoint/process +4. Document the deletion request process with a timeline (max 30 days under APPs) + +#### 1.1.6 [HIGH] Cookie & Tracking Disclosure + +**Current State:** No Cookie Policy exists. Google AdSense is loaded on the page. + +**Issues Identified:** +- Google AdSense uses cookies and tracking technologies +- `zustand` persist middleware uses `localStorage` (key: `paychecker-storage-v2`) +- No cookie banner or consent mechanism exists +- EU visitors (GDPR) and some Australian state laws may require explicit cookie consent +- `ads.txt` confirms Google AdSense publisher ID `pub-4516626856296531` + +**Required Actions:** +1. Implement a Cookie Consent Banner (required for ad-supported sites) +2. Create a Cookie Policy page +3. Categorize cookies: Necessary / Analytics / Advertising +4. Allow users to accept/reject non-essential cookies +5. Don't load AdSense scripts until cookie consent is obtained + +#### 1.1.7 [HIGH] Notifiable Data Breaches Scheme (NDB) + +**Current State:** No data breach response plan exists. + +**Issues Identified:** +- Under the Privacy Act, if an eligible data breach occurs, you must notify affected individuals and the OAIC within 30 days +- Financial data (income, tax estimates, employer info) qualifies as data likely to cause serious harm +- No incident response plan documented +- No breach notification template prepared + +**Required Actions:** +1. Create a Data Breach Response Plan +2. Prepare breach notification templates (for OAIC and users) +3. Implement security monitoring on Supabase +4. Define breach severity assessment criteria +5. Establish a 72-hour initial assessment timeline + +#### 1.1.8 [MEDIUM] Children's Privacy + +**Current State:** No age verification or restriction. + +**Issues Identified:** +- No minimum age requirement stated +- Working holiday visa holders are typically 18-35, but student visa holders may include minors (under 18) +- Enhanced protections apply for children's data under APPs + +**Required Actions:** +1. Add minimum age requirement (13 or 16) to Terms of Service +2. Add age confirmation during sign-up +3. If allowing under-18 users, implement parental consent mechanisms + +#### 1.1.9 [MEDIUM] Email Communication Compliance (Spam Act 2003) + +**Current State:** Email addresses are collected but no email marketing system is evident. + +**Issues Identified:** +- The Spam Act 2003 requires opt-in consent for commercial electronic messages +- Password reset and verification emails are transactional (exempt) +- Any future promotional emails MUST have opt-in consent and unsubscribe mechanism +- Contact emails (`support@paychecker-six.vercel.app`) suggest potential for email communication + +**Required Actions:** +1. Ensure all Supabase transactional emails are properly configured +2. If planning email marketing, implement double opt-in +3. Include unsubscribe links in all commercial messages +4. Keep records of email consent + +#### 1.1.10 [LOW] De-identification & Analytics + +**Current State:** No analytics system identified beyond basic technical logs. + +**Required Actions:** +1. If adding analytics (Google Analytics, Mixpanel, etc.), update Privacy Policy +2. Implement IP anonymization +3. Consider privacy-focused alternatives (Plausible, Fathom) + +--- + +## 2. FINANCIAL DISCLAIMERS & REGULATORY COMPLIANCE + +### 2.1 [CRITICAL] Financial Services Disclaimer + +**Current State:** The Terms of Service states "It is not payroll software, legal advice, or tax advice." The About page has a similar disclaimer. However, the app actively calculates tax estimates using ATO tax brackets and PAYG withholding coefficients. + +**Issues Identified:** +- Calculating tax estimates with ATO data creates an implied advisory relationship +- The marketing material says "Tax Made Easy" and "Real-time tax estimates based on current ATO brackets" +- Promotional content claims "Accurate Pay Calculations" and "정확한 급여 계산" +- These claims may constitute providing financial product advice under the **Corporations Act 2001** +- Without an **Australian Financial Services Licence (AFSL)**, providing financial advice is illegal +- The disclaimer buried in ToS/About pages is insufficient if promotional materials contradict it + +**Required Actions:** +1. **Strengthen ALL disclaimers** - Add prominent, unavoidable disclaimers: + - On every page that shows tax calculations + - In the Dashboard component where tax estimates appear + - In the Fiscal Year view + - In all export files (CSV, PDF, ICS) +2. **Revise marketing language** - Remove words like: + - "Accurate" (replace with "estimated") + - "Tax Made Easy" (implies tax advisory) + - "정확한 급여 계산" (accurate pay calculation) + - "Real-time tax estimates based on current ATO brackets" (implies professional-grade accuracy) +3. Add in-app banner: *"These are estimates only. Always verify with your payslip, employer, or a registered tax agent."* +4. Consider consulting with a financial services lawyer + +### 2.2 [CRITICAL] Tax Agent Services Act 2009 + +**Current State:** The app provides tax withholding estimates using PAYG coefficients from ATO NAT 1004 Schedule 1. + +**Issues Identified:** +- Under the Tax Agent Services Act 2009, it is illegal to provide a "tax agent service" for a fee (or in connection with a commercial activity like AdSense) without being registered with the Tax Practitioners Board (TPB) +- "Tax agent service" includes preparing returns, providing advice on tax obligations, or applying tax laws to specific circumstances +- PayChecker applies specific ATO tax tables to individual user income = potentially a tax agent service +- The ads generate commercial revenue alongside the tax calculation feature + +**Required Actions:** +1. Obtain legal opinion from a tax law specialist on whether PayChecker constitutes a "tax agent service" +2. If required, register with the **Tax Practitioners Board** or restructure the service +3. At minimum, add prominent disclaimers on every tax-related screen: + - *"This is not tax advice. Consult a registered tax agent for your tax obligations."* +4. Add the disclaimer in ALL tax calculation exports +5. Consider labeling tax features as "educational estimates" rather than "calculations" + +### 2.3 [HIGH] Accuracy of ATO Tax Data + +**Current State:** Tax rates reference 2025-26 Financial Year. PAYG coefficients are from NAT 1004 (Stage 3 Tax Cuts, effective 1 July 2024). + +**Issues Identified:** +- Tax brackets and PAYG coefficients change annually +- Medicare Levy threshold (currently $27,222) changes annually +- Superannuation rate changes (currently 12%, scheduled increases) +- Working Holiday Maker rates may change +- Stale data = incorrect estimates = potential liability + +**Required Actions:** +1. Implement a systematic annual review process aligned with ATO announcements (typically May-June each year) +2. Display the financial year the calculations apply to prominently +3. Add "Last updated" timestamps on tax calculation screens +4. Create automated tests that flag when rates should be reviewed +5. Add a warning if a user's shift dates span multiple financial years + +### 2.4 [HIGH] Superannuation Rate Display + +**Current State:** `SUPER_RATE = 0.115` in `useScheduleStore.ts` but `AU_SUPER_RATE = 0.12` in `australia.ts`. + +**Issues Identified:** +- **INCONSISTENCY**: Two different super rates in the codebase (11.5% vs 12%) +- The Export modal uses `SUPER_RATE` (11.5%) while tax calculations use `AU_SUPER_RATE` (12%) +- SG rate as of 1 July 2025 is 12% +- Incorrect super calculations could mislead users + +**Required Actions:** +1. **IMMEDIATELY fix the inconsistency** - unify to 12% (or whatever the current rate is) +2. Source super rate from a single constant +3. Display the applicable period for super rate +4. Add automated test to catch rate inconsistencies + +### 2.5 [HIGH] Korean Tax Rates - Disclaimer Gap + +**Current State:** Korean tax calculations exist in `korea.ts` (2024 tax brackets, 4대보험 rates) but the Korean calculator is referenced but not fully integrated. + +**Issues Identified:** +- Korean tax rates are labeled "2024 기준" - already potentially out of date for 2026 +- No disclaimer specific to Korean tax calculations +- Different regulatory framework applies (Korean tax law, not Australian) +- Country selection is limited to 'AU' in `countries.ts` but code exists for Korea +- If re-enabled, Korean financial disclosure requirements would apply + +**Required Actions:** +1. Either completely remove Korean tax code before launch, or +2. Fully validate Korean rates for 2026 +3. Add Korean-specific financial disclaimers if the feature is enabled +4. Consult Korean tax law requirements for digital tax tools + +### 2.6 [MEDIUM] Pay Estimation Accuracy Disclaimers + +**Current State:** Basic disclaimer in footer and About page. + +**Issues Identified:** +- No disclaimer is shown in: + - The Dashboard summary cards (Est. Pay, Net Pay, Tax) + - The Fiscal Year view (YTD Income, Tax Withheld, Est. Return) + - The Export modal (preview amounts) + - CSV/PDF export files +- Users may rely on these figures for financial decisions + +**Required Actions:** +1. Add an informational tooltip or footnote to every monetary value displayed +2. Include disclaimer text in all exported files +3. The footer disclaimer should be more prominent (currently `text-xs`) + +### 2.7 [MEDIUM] Visa Work Hour Compliance Feature + +**Current State:** The `VisaWarningModal` warns about 48-hour fortnightly limits for student visa holders. + +**Issues Identified:** +- This feature implies the app helps with visa compliance +- Student visa work conditions are complex and change frequently +- The 48-hour limit has exceptions (e.g., during course breaks, post-July 2023 changes) +- Reliance on this feature for visa compliance could have serious immigration consequences + +**Required Actions:** +1. Add a prominent disclaimer: *"This feature is for planning only. Verify work hour limits with the Department of Home Affairs."* +2. Link to official government resources +3. Do NOT market this as a visa compliance tool + +--- + +## 3. TERMS OF SERVICE & CONTRACTUAL REQUIREMENTS + +### 3.1 [CRITICAL] Governing Law & Jurisdiction + +**Current State:** Terms of Service has no governing law clause. + +**Issues Identified:** +- No applicable law specified (should be Australian law, specific state) +- No jurisdiction for dispute resolution +- No arbitration or mediation clause +- International users (Korea, other countries) need clarity on which law applies + +**Required Actions:** +1. Add governing law clause (e.g., "Laws of New South Wales, Australia") +2. Add jurisdiction clause for dispute resolution +3. Consider adding a dispute resolution process (mediation before litigation) + +### 3.2 [HIGH] Australian Consumer Law (ACL) Compliance + +**Current State:** Terms include "as is" and limitation of liability clauses. + +**Issues Identified:** +- Under ACL, consumer guarantees **cannot be excluded** for consumer services +- The "as is" disclaimer may be void to the extent it conflicts with consumer guarantees +- Service must be provided with "due care and skill" and be "fit for purpose" +- If the service is free, ACL may have more limited application, but advertising and promotional materials must still comply + +**Required Actions:** +1. Add ACL disclaimer: *"Nothing in these Terms excludes your rights under Australian Consumer Law"* +2. Remove or qualify the "as is" clause for Australian consumers +3. Review promotional claims against ACL misleading conduct provisions + +### 3.3 [HIGH] User Content & Intellectual Property + +**Current State:** No clause addressing ownership of user-created data. + +**Issues Identified:** +- Users create valuable data (shift records, job configs, expense records) +- No clause confirming users retain ownership of their data +- No license grant clause for how PayChecker can use uploaded data +- Roster images may be employer intellectual property + +**Required Actions:** +1. Add "User Content" clause specifying: + - Users retain ownership of their data + - PayChecker receives a limited license to process data for service delivery + - Users warrant they have rights to upload content (especially roster images) +2. Add data portability provision (users can export all their data) + +### 3.4 [HIGH] Account Deletion & Data Portability + +**Current State:** Privacy Policy mentions "You may request account deletion" but no mechanism exists. + +**Issues Identified:** +- No in-app account deletion feature +- No documented process for data export (beyond CSV/PDF of shifts) +- No response timeline for deletion requests +- Under APPs, users have a right to access and correction + +**Required Actions:** +1. Implement in-app account deletion +2. Implement full data export (all tables: profile, jobs, shifts, expenses, feedback) +3. Document the process with a maximum 30-day timeline +4. Confirm data is actually deleted from Supabase (not just soft-deleted) + +### 3.5 [MEDIUM] Service Level & Availability + +**Current State:** Terms state "We may modify, suspend, or discontinue features at any time." + +**Required Actions:** +1. Add notice period for significant changes (e.g., 30 days) +2. Define the process for notifying users of changes +3. Address what happens to user data if the service shuts down + +### 3.6 [MEDIUM] Indemnification Clause + +**Current State:** No indemnification clause exists. + +**Required Actions:** +1. Add user indemnification for: + - Uploading content they don't have rights to + - Misuse of the service + - Reliance on estimates for tax or payroll purposes +2. Ensure indemnification is reasonable and balanced + +--- + +## 4. ADVERTISING & MARKETING COMPLIANCE + +### 4.1 [CRITICAL] Google AdSense Policy Compliance + +**Current State:** AdSense is active with publisher ID `ca-pub-4516626856296531`. The `ads.txt` file is configured. + +**Issues Identified:** +- Google AdSense requires a published Privacy Policy (EXISTS, but needs updates) +- Google's EU User Consent Policy requires consent for EEA/UK users +- Ad placement must follow Google policies (no misleading placement, click encouragement, etc.) +- Financial services content has special AdSense policies - tax calculation pages may require additional review +- Must comply with Better Ads Standards + +**Required Actions:** +1. Review and ensure Privacy Policy meets Google's requirements +2. Implement Google's Consent Management Platform (CMP) for EU/UK users +3. Verify ad placement follows Google's policies +4. Review if financial content triggers Google's "sensitive category" policies +5. Ensure ads are clearly labeled as advertisements (currently done: `aria-label="Advertisement"`) + +### 4.2 [HIGH] Australian Competition and Consumer Commission (ACCC) - Misleading Claims + +**Current State:** Marketing materials contain bold claims. + +**Issues Identified:** +- "Accurate Pay Calculations" - may be misleading if estimates differ from actual pay +- "100% free, no premium tier" - must remain true or be updated +- "정확한 급여 계산" (accurate pay calculation) - same issue in Korean +- "Introducing PayChecker - A Free Roster & Pay Management App" - "Free" claim requires that it be truly free (no hidden costs, in-app purchases, or data monetization beyond ads) +- Marketing claims that the tool helps with "88일 계산용 기록" (88 days calculation) for working holiday visa second year - this is immigration-adjacent advice + +**Required Actions:** +1. Audit ALL promotional content for potentially misleading claims +2. Replace "accurate" with "estimated" or "approximate" +3. Ensure "free" claims remain valid +4. Add appropriate qualifiers to all claims +5. Remove or heavily qualify immigration-related claims + +### 4.3 [HIGH] Platform-Specific Promotional Rules + +**Current State:** `marketing/promotional-content.md` contains ready-made posts for Reddit, Product Hunt, LinkedIn, Facebook, Korean communities. + +**Issues Identified:** +- Reddit has strict self-promotion policies (many subreddits ban or limit promotional posts) +- r/australia, r/AusFinance have specific rules about commercial posts +- Korean community platforms (호주나라, 마이호주, 워홀프렌즈) may have advertising restrictions +- Product Hunt requires honest disclosure +- LinkedIn has sponsored content policies +- Facebook has advertising policies and financial services restrictions + +**Required Actions:** +1. Review each target platform's rules BEFORE posting +2. Mark posts as promotional where required +3. Follow Reddit's 10% self-promotion rule +4. Prepare for community backlash by having responses ready +5. Consider paid advertising channels where organic promotion is restricted + +### 4.4 [MEDIUM] Testimonials & User Reviews + +**Current State:** No testimonials or reviews system exists. + +**Required Actions (if adding):** +1. Any testimonials must be genuine and verifiable +2. Must disclose material connections (e.g., if incentivized) +3. Must not be misleading about typical user experience + +### 4.5 [MEDIUM] SEO & Meta Tag Claims + +**Current State:** `index.html` contains SEO meta tags. + +**Issues Identified:** +- Meta description: "Track schedules, estimate earnings, and export records for tax-season prep" - the phrase "tax-season prep" should be qualified +- Keywords include "australia pay calculator" - could imply official/authoritative status +- og:description: "Track rosters, estimate shift earnings, and manage work records in one place" - reasonable + +**Required Actions:** +1. Review meta descriptions for accuracy +2. Avoid keywords that imply official or government-endorsed status +3. Use consistent language across all pages + +### 4.6 [MEDIUM] Affiliate & Referral Disclosure + +**Current State:** No affiliate or referral programs exist. + +**Required Actions (if adding):** +1. Disclose any affiliate relationships +2. Follow ACCC disclosure requirements +3. Ensure transparency in any partnership promotions + +### 4.7 [LOW] Trademark Considerations + +**Current State:** Using "PayChecker" as a brand name. + +**Required Actions:** +1. Search the IP Australia trademark register for conflicts +2. Search ASIC for business name conflicts +3. Consider registering "PayChecker" as a trademark +4. Ensure no confusion with existing financial services brands + +--- + +## 5. ACCESSIBILITY & ANTI-DISCRIMINATION + +### 5.1 [HIGH] Web Content Accessibility Guidelines (WCAG) Compliance + +**Current State:** Some accessibility features exist (aria-labels, focus-visible styles, min touch targets of 48px), but no systematic WCAG audit has been conducted. + +**Issues Identified:** +- No WCAG conformance level declared +- The **Disability Discrimination Act 1992 (DDA)** applies to websites accessible in Australia +- Government guidelines recommend WCAG 2.1 Level AA compliance +- Color-coded job indicators (using Tailwind color names) may be inaccessible to color-blind users +- Drag-and-drop interaction (DnD Kit) may not be keyboard accessible +- Modal dialogs should trap focus +- PDF exports should be accessible + +**Required Actions:** +1. Conduct WCAG 2.1 Level AA audit +2. Fix identified accessibility issues +3. Add a WCAG conformance statement to the website +4. Ensure all interactive elements are keyboard navigable +5. Test with screen readers (NVDA, VoiceOver) +6. Add text labels alongside color indicators +7. Ensure modals have proper focus management + +### 5.2 [HIGH] Language Accessibility + +**Current State:** App is primarily English. Korean translations exist but the country is locked to 'AU'. Some UI strings are hardcoded in English (e.g., "Visa Limit Warning", "Don't Add Shift"). + +**Issues Identified:** +- Target audience includes Korean speakers (marketing content exists in Korean) +- Some Korean comments exist in source code (`// 휴가 기간 추가 시 즉시 Supabase에 저장`) +- i18n infrastructure exists but is incomplete +- Mixed language experience could confuse users + +**Required Actions:** +1. Complete Korean translations if targeting Korean speakers +2. Or remove Korean marketing materials if not supporting Korean UI +3. Ensure all user-facing strings go through i18n +4. Add language selector if supporting multiple languages + +### 5.3 [MEDIUM] Mobile Accessibility + +**Current State:** Responsive design with mobile-specific UI adaptations. + +**Required Actions:** +1. Test on assistive technology across iOS/Android +2. Ensure touch targets meet 48x48dp minimum +3. Test with dynamic font sizes +4. Ensure modals work properly on mobile screen readers + +### 5.4 [MEDIUM] Cultural Sensitivity + +**Current State:** Targets visa holders (working holiday, student visa) which includes diverse cultural backgrounds. + +**Required Actions:** +1. Review all content for cultural sensitivity +2. Avoid stereotyping (e.g., "backpackers = fruit picking") +3. Ensure examples are inclusive +4. Consider adding language support for other common languages (Mandarin, Japanese) + +### 5.5 [LOW] Right-to-Left (RTL) Support + +**Required Actions:** +1. If expanding to RTL languages, implement RTL layout support +2. Low priority for current audience + +--- + +## 6. INTELLECTUAL PROPERTY + +### 6.1 [HIGH] Open-Source License Compliance + +**Current State:** `package.json` lists 20+ dependencies. No license field in `package.json`. No `LICENSE` file in the repository. + +**Issues Identified:** +- Each dependency has its own license (MIT, Apache 2.0, ISC, etc.) +- Some may have attribution requirements +- No license file declares the project's own license +- If using any copyleft (GPL) dependencies, the entire codebase may need to be open-sourced + +**Required Actions:** +1. Run `npx license-checker --summary` to audit all dependency licenses +2. Ensure no GPL-licensed dependencies are included (or comply with GPL) +3. Add a `LICENSE` file declaring the project's license +4. Create a `THIRD_PARTY_LICENSES` file listing all dependency licenses +5. Add attribution for all required licenses + +### 6.2 [MEDIUM] ATO Data Usage + +**Current State:** Tax brackets and PAYG coefficients are sourced from ATO publications. + +**Issues Identified:** +- ATO data is Crown Copyright (Commonwealth of Australia) +- May be used under Creative Commons Attribution license +- Attribution to the ATO may be required +- "Reference" URLs in code comments are good but insufficient for public attribution + +**Required Actions:** +1. Add ATO attribution statement: *"Tax rates sourced from the Australian Taxation Office. Commonwealth of Australia."* +2. Review ATO's data use terms +3. Include in a "Data Sources" section of the About page + +### 6.3 [MEDIUM] Google Gemini API - Usage Terms + +**Current State:** Roster images are sent to Google Gemini for OCR/extraction. + +**Issues Identified:** +- Google Gemini API has specific terms about data usage and retention +- API usage may have rate limits and acceptable use policies +- Must comply with Google Cloud Terms of Service + +**Required Actions:** +1. Review and comply with Google Gemini API terms +2. Ensure data handling meets Google's requirements +3. Disclose AI usage in Privacy Policy and Terms of Service + +### 6.4 [LOW] Brand Assets & Third-Party Logos + +**Current State:** No third-party logos detected in the codebase. + +**Required Actions:** +1. If adding logos (Google, Supabase, etc.), ensure compliance with their brand guidelines +2. Do not imply endorsement by third parties + +--- + +## 7. PLATFORM & TECHNICAL COMPLIANCE + +### 7.1 [CRITICAL] Security Audit Before Launch + +**Current State:** CI pipeline includes lint, build, test, audit. RLS (Row Level Security) is enabled on all Supabase tables. + +**Issues Identified:** +- No dedicated security audit has been performed +- `npm audit --omit=dev --audit-level=high` is only for production dependencies +- No penetration testing +- `dangerouslySetInnerHTML` check exists but other XSS vectors may exist +- Service role key handling in Edge Function needs review +- CORS configuration accepts all `*.vercel.app` URLs containing "paychecker" + +**Required Actions:** +1. Conduct a security audit (OWASP Top 10 review) +2. Penetration testing on the Supabase Edge Function +3. Review all RLS policies for completeness +4. Implement Content Security Policy (CSP) headers +5. Add rate limiting to the Edge Function (beyond scan limits) +6. Review CORS policy - tighten to specific production domains only +7. Ensure `.env` files are never committed (`.gitignore` has this) +8. Review Supabase auth configuration (email verification required?) + +### 7.2 [HIGH] HTTPS & Transport Security + +**Current State:** Vercel provides automatic HTTPS. Supabase Edge Functions are HTTPS. + +**Required Actions:** +1. Verify HSTS headers are set +2. Ensure all resources are loaded over HTTPS +3. Set `Strict-Transport-Security` header +4. Consider Certificate Transparency monitoring + +### 7.3 [HIGH] Content Security Policy + +**Current State:** No CSP headers configured. + +**Issues Identified:** +- Google AdSense requires specific CSP directives +- External scripts (AdSense) loaded without nonce/hash +- No protection against XSS via CSP + +**Required Actions:** +1. Implement CSP headers in Vercel configuration +2. Use nonce-based CSP for inline scripts +3. Whitelist required external domains (Google AdSense, Supabase) + +### 7.4 [MEDIUM] Data Backup & Disaster Recovery + +**Current State:** Relies on Supabase's built-in backup. + +**Required Actions:** +1. Document the backup strategy +2. Verify Supabase's backup and recovery capabilities for your plan +3. Test data restoration procedure +4. Implement export-all functionality for users + +### 7.5 [MEDIUM] Error Handling & Information Disclosure + +**Current State:** Errors are logged to console in DEV mode. Production error handling exists. + +**Issues Identified:** +- `import.meta.env.DEV` guards are good for DEV-only logging +- Edge Function health check exposes configuration status (which keys are set) +- Error responses include `requestId` (good for debugging, ensure it doesn't leak info) + +**Required Actions:** +1. Ensure production builds don't expose sensitive debugging information +2. Review Edge Function health endpoint exposure +3. Implement centralized error tracking (Sentry or similar) + +### 7.6 [MEDIUM] Vercel Deployment Compliance + +**Current State:** Deployed on Vercel free tier (implied by paychecker-six.vercel.app domain). + +**Issues Identified:** +- Vercel's free tier has usage limits +- Vercel's Terms of Service apply +- If using commercial features (AdSense revenue), may need a paid Vercel plan +- Custom domain recommended for production launch + +**Required Actions:** +1. Review Vercel's Terms for commercial use on free tier +2. Set up custom domain (not `*.vercel.app`) +3. Ensure Vercel plan supports expected traffic +4. Configure proper DNS and SSL for custom domain + +--- + +## 8. INTERNATIONAL & VISA-SPECIFIC CONSIDERATIONS + +### 8.1 [HIGH] GDPR Compliance (EU/EEA Users) + +**Current State:** No GDPR compliance measures exist. + +**Issues Identified:** +- Working holiday visa holders may be from EU/EEA countries +- If ANY EU/EEA user accesses the service, GDPR applies +- GDPR requires: + - Lawful basis for processing + - Data Protection Officer (DPO) if processing at scale + - Right to erasure, portability, restriction + - Privacy by design and by default + - 72-hour breach notification +- Google AdSense serving to EU users triggers GDPR requirements + +**Required Actions:** +1. Implement GDPR consent mechanisms +2. Add GDPR-specific privacy provisions +3. Implement right to erasure and data portability +4. Consider using Google's Consent Mode for EU users +5. Review if a DPO appointment is needed + +### 8.2 [HIGH] Korean Personal Information Protection Act (PIPA) + +**Current State:** Korean marketing materials exist. Korean tax code exists in the codebase. + +**Issues Identified:** +- If targeting Korean users (as marketing suggests), PIPA applies +- PIPA requirements are similar to GDPR but with Korean-specific obligations +- Korean users have specific rights under PIPA +- Cross-border transfer restrictions apply + +**Required Actions:** +1. If targeting Korean users: + - Comply with PIPA requirements + - Provide Korean-language privacy notice + - Implement Korean-specific consent mechanisms +2. If NOT targeting Korean users: + - Remove Korean marketing materials + - Remove Korean tax code + - Block or redirect Korean IP addresses (optional) + +### 8.3 [MEDIUM] Immigration Disclaimer + +**Current State:** The app tracks visa type and work hours for student visa compliance. + +**Issues Identified:** +- Providing immigration-related guidance without being a registered migration agent is restricted under the Migration Act 1958 +- Marketing claims about tracking "88 days" for working holiday visa extensions +- The visa work hour tracking could be seen as providing immigration assistance + +**Required Actions:** +1. Add prominent immigration disclaimer +2. Remove references to "88 days" tracking +3. State that the app does not provide immigration advice +4. Link to official Department of Home Affairs resources + +### 8.4 [MEDIUM] Multi-Currency & Tax Jurisdiction + +**Current State:** Locked to AUD currency for AU users. + +**Issues Identified:** +- If expanding to other countries, each jurisdiction has its own: + - Tax rates and brackets + - Privacy laws + - Financial services regulations + - Consumer protection laws + +**Required Actions:** +1. For each new country/currency, conduct a separate compliance review +2. Do not launch Korean features without Korean regulatory review + +--- + +## 9. CONTACT & SUPPORT EMAIL VALIDITY + +### 9.1 [MEDIUM] Professional Contact Information + +**Current State:** Support email is `support@paychecker-six.vercel.app` + +**Issues Identified:** +- Using a Vercel subdomain for email is unprofessional and may not work +- Contact page lists `partners@paychecker-six.vercel.app` for business inquiries +- These email addresses may not actually receive mail (Vercel doesn't provide email hosting) +- Privacy Policy and Terms reference these potentially non-functional emails + +**Required Actions:** +1. Set up a custom domain with working email +2. Verify all listed email addresses actually receive and send mail +3. Update all references if email addresses change +4. Consider a support ticket system for accountability + +--- + +## 10. PRE-LAUNCH COMPLIANCE CHECKLIST + +### Must Do Before Launch (CRITICAL) + +- [ ] Fix super rate inconsistency (11.5% vs 12%) +- [ ] Strengthen financial/tax disclaimers on ALL calculation screens +- [ ] Update Privacy Policy with complete data processor disclosures +- [ ] Add cross-border data transfer disclosures +- [ ] Implement Cookie Consent Banner +- [ ] Add governing law clause to Terms of Service +- [ ] Conduct security audit (OWASP Top 10) +- [ ] Verify contact emails actually work + +### Must Do Within 30 Days of Launch (HIGH) + +- [ ] Complete WCAG 2.1 AA accessibility audit +- [ ] Implement account deletion feature +- [ ] Create Data Breach Response Plan +- [ ] Implement Content Security Policy headers +- [ ] Audit all dependency licenses +- [ ] Review marketing materials for misleading claims +- [ ] Add ATO data attribution +- [ ] Obtain legal opinion on Tax Agent Services Act applicability +- [ ] Set up custom production domain +- [ ] Add data retention periods to Privacy Policy +- [ ] Implement GDPR consent mechanisms +- [ ] Review Google AdSense financial content policies +- [ ] Add AI processing disclosure for roster uploads +- [ ] Implement data portability (full export) +- [ ] Set up HSTS headers +- [ ] Add minimum age requirement +- [ ] Review and update Korean marketing materials or remove them +- [ ] Add user content ownership clause to Terms +- [ ] Add ACL savings clause to Terms + +### Should Do Within 90 Days (MEDIUM) + +- [ ] Conduct penetration testing +- [ ] Implement centralized error monitoring +- [ ] Complete all i18n translations or remove untranslated content +- [ ] Create THIRD_PARTY_LICENSES file +- [ ] Add Cookie Policy page +- [ ] Implement automated data retention/purge +- [ ] Test with screen readers and assistive technology +- [ ] Review cultural sensitivity of content +- [ ] Add "Data Sources" section to About page +- [ ] Implement proper backup verification process +- [ ] Set up monitoring and alerting +- [ ] Prepare a Data Breach notification template + +--- + +*End of Legal Compliance Report*