Appearance
Privacy & Compliance
Spec Source: Document 10 -- Data Security & Privacy, Document 14 -- Legal & Policies | Cross-refs: Doc 1 (COPPA/Accounts), Doc 6 (FERPA/Schools), Doc 9 (Audit Logging) | Last Updated: February 2026
DoCurious collects and processes data from minors, students, parents, teachers, and general users across multiple regulatory jurisdictions. Privacy and compliance are not afterthought features -- they are structural constraints that shape every data flow, UI decision, and API endpoint on the platform.
STATUS: BUILT
The frontend implements cookie consent (3-category banner with Zustand persistence), data export request pages, data subject access request (DSAR) forms, account deletion with 30-day grace period, COPPA-aware route guards (AgeGuard, ConsentGuard), parental consent types in the auth system, and privacy settings on user profiles. Backend enforcement (encryption at rest, key management, FERPA data isolation, real audit logging, breach notification workflows) is not yet implemented. Legal document pages (Terms of Service, Privacy Policy, AUP, etc.) are referenced but not yet created as viewable content pages.
Overview
DoCurious operates under a web of overlapping privacy regulations because it serves minors in school contexts:
| Regulation | Applies Because | Key Requirements |
|---|---|---|
| COPPA | Users under 13 | Verifiable parental consent, data minimization, deletion rights |
| FERPA | Student education records via schools | School controls access, parent rights, no unauthorized disclosure |
| CCPA/CPRA | California users | Right to know, delete, opt-out; stricter rules for minors |
| State Student Privacy Laws | Schools in various states | Varies by state; many require signed data processing agreements |
| GDPR | If serving EU users (future) | Consent, data minimization, right to erasure, DPO requirement |
The platform's privacy architecture is organized around three pillars:
- Data classification -- Four sensitivity tiers determining how each piece of data is stored, encrypted, accessed, and retained
- Regulatory compliance -- COPPA two-tier consent, FERPA school-as-controller model, GDPR/CCPA data subject rights
- Legal documents -- Nine required policy documents that must exist before launch
How It Works
Data Classification (4 Tiers)
STATUS: PLANNED
The four-tier classification system is fully specified but not yet enforced at the database or API level. The frontend type system models the data categories, and the privacy settings UI reflects user-controlled visibility. Backend implementation of column-level encryption, row-level security, and audit logging per tier is pending.
All data handled by the platform is classified into sensitivity tiers that determine storage, access, and retention requirements:
Tier 1: Restricted (Highest Sensitivity)
Data that could cause significant harm if exposed. Access limited to system processes only -- no human access to raw data.
| Data | Examples | Requirements |
|---|---|---|
| Authentication secrets | Hashed passwords, session keys, auth tokens | AES-256 at rest, logged access attempts, 90-day key rotation |
| Consent records | Parental consent verification, consent IP addresses | AES-256 at rest, immutable audit trail |
| Payment references | External payment IDs (Stripe account references) | AES-256 at rest, no raw card data stored |
| Security infrastructure | Encryption keys, admin impersonation logs | KMS-managed, multi-factor access required |
Tier 2: Confidential (PII)
Personally identifiable information and protected records. Access restricted by role on a need-to-know basis.
| Data | Examples | Requirements |
|---|---|---|
| Contact information | Email addresses, phone numbers, physical addresses | Column-level encryption, audit logged |
| Identity data | Full (real) names, dates of birth | Column-level encryption, subject to deletion requests |
| Relationship records | Parent-child links, student-school associations | Encrypted, role-scoped access |
| Education records | Track Records in school context, reflection responses | FERPA-protected, school-scoped access |
| Technical identifiers | IP addresses, device identifiers | Encrypted, 90-day retention for security logs |
Tier 3: Internal
Operational data not publicly visible but low sensitivity. Standard database security with role-based access.
- Display names, user preferences and settings
- Challenge progress data, XP, levels, badges
- Community membership, Bucket List / Interesting List
- Internal analytics aggregates
Tier 4: Public
Data intentionally shared by users. Standard security, user-controlled visibility, removable by user request.
- Public profile information and shared Track Records
- Community posts and published portfolio content
- Challenge content (vendor-created) and vendor profiles
Special Data Categories
Minor Data (Under-18): All data from users under 18 receives enhanced protections regardless of tier -- minimized collection, shorter retention, no sale or sharing with third parties, no behavioral advertising.
Under-13 Data (COPPA-Protected): Additional restrictions beyond minor data -- verifiable parental consent before collection, parent access and deletion rights, annual consent renewal recommended, no persistent identifiers for advertising.
Student Education Records (FERPA-Protected): Data generated within school context -- school is data controller, DoCurious is data processor. Only school-authorized personnel can access. Parent rights to inspect and request amendment.
Encryption
STATUS: PLANNED
Encryption specifications are fully defined in the spec. No backend encryption implementation exists yet. The frontend does not handle encryption directly -- this is entirely a backend/infrastructure concern.
Data in Transit:
- All network communication uses TLS 1.2 or higher
- HTTP Strict Transport Security (HSTS) header with minimum 1-year max-age and includeSubDomains
- Automated certificate renewal (Let's Encrypt or managed service)
- No self-signed certificates in production
Data at Rest:
- AES-256 encryption for all Tier 1 data and database-level storage
- Column-level encryption for select Tier 2 fields: email addresses, real names, dates of birth, phone numbers, IP addresses, parental consent records
- Even database administrators cannot read encrypted fields without the application decryption key
Key Management:
- Keys stored in dedicated KMS (AWS KMS, GCP KMS, or equivalent)
- Key access logged and requires multi-factor authentication
- Rotation schedule: 90 days for Tier 1, 1 year for others
- Separate keys per environment (dev, staging, production)
- No keys in source code, config files, or environment variables on disk
| Data Type | Encryption | Key Management |
|---|---|---|
| Database | AES-256 (full disk or column-level) | AWS KMS, GCP KMS, or equivalent |
| File Storage (media) | AES-256 (S3 SSE or equivalent) | Managed by cloud provider |
| Backups | AES-256 | Separate key from production |
| Logs | AES-256 | Rotated separately |
| Session Store | Encrypted (Redis TLS) | Ephemeral keys |
Authentication Security
STATUS: BUILT
Authentication security is fully implemented with JWT-based auth, rate limiting middleware, MFA (TOTP-based) with QR code setup and backup codes, and account lockout after failed attempts. The backend enforces rate limiting on auth endpoints and the frontend provides the full MFA enrollment and verification flow.
Password Security:
- Hashing: bcrypt (cost factor 12+) or Argon2id -- raw passwords never stored, logged, or transmitted in plaintext
- Per-user salt (automatic with bcrypt/Argon2)
- Minimum 8 characters, no maximum cap (up to 128)
- Checked against common password lists (HaveIBeenPwned top 100k)
- No arbitrary complexity rules -- length is prioritized over character diversity
- Breach notification if password found in known breach databases
- Password reset: time-limited token (1-hour expiry), single-use, rate limited (max 3 per hour per email)
- All existing sessions invalidated on password change
OAuth / Social Login:
- Supported providers: Google OAuth 2.0, Apple Sign In
- Server-side ID token validation with issuer, audience, and expiry verification
- PKCE (Proof Key for Code Exchange) for mobile
- Only necessary claims stored (email, name, provider ID)
- Account linking supported (OAuth + email/password for the same account)
Rate Limiting & Brute Force Protection:
| Endpoint | Limit | Lockout |
|---|---|---|
| Login | 5 attempts per 15 min per account | 15-minute lockout after 5 failures |
| Login (IP) | 20 attempts per 15 min per IP | IP-level throttle |
| Password reset | 3 per hour per email | Silently ignore excess |
| Registration | 5 per hour per IP | IP-level throttle |
| API (authenticated) | 100 requests per minute | 429 response |
| API (unauthenticated) | 20 requests per minute | 429 response |
| File upload | 10 per minute | 429 response |
| Verification submission | 10 per day per user | Soft block + notification |
Progressive account lockout escalates: 15 minutes after 5 failures, 30 minutes after 10, 1 hour after 15. No indication of whether an email exists (prevents enumeration).
Session Management
STATUS: BUILT
The SessionInfo type is defined with userId, role, issuedAt, expiresAt, and deviceInfo. The AuthTokens type models access and refresh tokens with expiry. The auth store manages session initialization and logout. Backend session infrastructure (HttpOnly cookies, concurrent session limits, IP tracking, admin-specific timeouts) is not yet implemented.
Session Configuration:
- Session token: cryptographically random (256-bit minimum)
- HttpOnly cookie (not accessible via JavaScript), Secure flag (HTTPS only), SameSite=Strict or Lax
- Session timeout: 30 days (with refresh)
- Idle timeout: 7 days of inactivity
- Session ID regenerated on login (prevents session fixation)
- Maximum concurrent sessions: configurable (default: 5)
- IP change within session: flagged but not immediately invalidated
Admin Sessions:
- Shorter timeout: 8 hours (vs 30 days for regular users)
- Shorter idle timeout: 1 hour
- Re-authentication required for sensitive actions
- All admin session activity logged
API Token Structure:
- JWT signed with RS256 (asymmetric key)
- JWT contains:
user_id,role,organization_id(if applicable),issued_at,expiry - Access token expiry: 15 minutes
- Refresh token expiry: 30 days
- Refresh token rotation: new refresh token issued with each access token refresh
Multi-Factor Authentication (MFA)
STATUS: BUILT
TOTP-based MFA is now implemented in both backend and frontend. Admin users have TOTP setup UI, backup code display, and MFA challenge screens. Backend supports TOTP verification with Google Authenticator and Authy.
Admin Users (Required):
- TOTP (Time-based One-Time Password) via Google Authenticator, Authy, etc.
- Backup codes (one-time use, stored hashed)
- Recovery requires Super Admin approval
General Users (Optional):
- TOTP support available but not required
- Email-based verification as fallback
COPPA Compliance
STATUS: BUILT
The COPPA type system is comprehensive: ConsentStatus enum (not_required | pending | granted | revoked), StudentAccountTier (tier_1_school_only | tier_2_parent_linked), ParentConsentRequest/ParentConsentConfirm types, ParentVerification with Stripe $1 credit card verification, and isUnder13 flag on users. Route guards (AgeGuard, ConsentGuard) enforce age-based and consent-based access. Frontend COPPA enforcement includes: parent-only account deletion for under-13 (48-hour COPPA timeline), CoppaPaymentVerification component with 4-step $1.00 mock payment flow, consent grant/revoke UI on Parent Dashboard (Tier 2 ↔ Tier 1 toggle), and data minimization (hidden optional PII fields + registration-time stripping for under-13). Backend consent record storage and annual renewal workflow are not yet implemented.
Age Verification at Registration:
- Date of birth collected (or age bracket)
- Under 13: redirected to Tier 1 (school) or Tier 2 (parent consent) flow
- 13--17: standard registration with minor-appropriate defaults
- 18+: standard registration
- Age gate does not store rejected attempts
- Cannot retry with a different age in the same session
- Date of birth cannot be changed after registration without admin review
Two-Tier Consent System:
| Tier 1: School-Only | Tier 2: Parent-Linked | |
|---|---|---|
| Authorization | School acts as COPPA agent (school exception) | Explicit parental consent via $1 credit card verification |
| Can do | School challenges, school Track Records, school communities, receive school gifts | Everything in Tier 1, plus friend communities, personal bucket lists, public sharing, personal gifts, full Explore |
| Cannot do | Friend communities, personal bucket lists, public sharing, personal gifts | -- |
| Consent record | School DPA | Parent user ID, child user ID, consent method, timestamp, IP, policy version, scope |
Parental Consent Records (What Is Stored):
- Parent user ID and child user ID
- Consent method (email verification, credit card verification)
- Consent timestamp and IP address of consent
- Privacy policy version at time of consent
- Consent scope (what data collection was consented to)
- Status: active or withdrawn
Consent Lifecycle:
- Parent can withdraw consent at any time
- Withdrawal triggers: stop data collection, delete child data (within 30 days), or anonymize
- Annual re-consent recommended (best practice, not legally required)
- Consent scope changes require new consent
Under-13 Data Restrictions:
- No persistent identifiers for tracking
- No geolocation collection
- No behavioral profiling
- Collect only: display name, age, parent's email, school affiliation
- Media uploads not scanned by third-party AI without parental consent
- No data shared with advertising networks or analytics services that create user profiles
FERPA Compliance
STATUS: PARTIAL
The school type system includes requireParentalConsent on the School entity, and the school store enforces role-based access to school data. The adapter layer maps organization_id for school scoping. However, the full FERPA enforcement model (school DPA execution workflow, row-level security in database, parent inspection rights UI, amendment request routing to schools) is not yet implemented.
Data Processing Agreement (DPA):
- Each school must sign a DPA before student data is processed
- DoCurious acts as a "school official" with "legitimate educational interest"
- Data use limited to providing educational services
- No re-disclosure of student records
- Data deletion upon contract termination
- Incident notification procedures specified
School as Data Controller:
- SA determines what features are enabled
- SA determines what data is collected (reflection prompts, etc.)
- SA can request data export or deletion for any student
- SA controls sharing settings at school level
Data Isolation Requirements:
- School data queries always scoped to
organization_id - No cross-school data access (even for teachers at multiple schools)
- Teacher can only see data for assigned classes
- Student can only see their own account
- Row-level security policies on database (where supported)
- Automated tests verifying isolation
Parent Rights Under FERPA:
- Right to inspect student's education records
- Right to request amendment of inaccurate records
- Right to consent before disclosure
- Rights transfer to student at age 18 (or upon college enrollment)
- Parent dashboard provides record inspection
- Amendment requests routed to school (DoCurious supports but school decides)
GDPR / CCPA Data Subject Rights
STATUS: BUILT
The DataAccessRequest page is fully interactive with four request types (Access, Correct, Restrict, Portability), conditional detail forms, identity verification notice, and request history with status tracking. The DataExportRequest page supports category selection (profile, Track Records, reflections, communities, messages) with export history. The AccountDeletion page implements the 30-day grace period flow with DELETE confirmation and reactivation notice. All pages use mock API calls.
Right to Access / Data Export:
Who can request:
- Any user (their own data)
- Parent (linked child's data, if child under 13)
- SA (student data within school, for FERPA compliance)
What is included: profile information, all Track Records (text + media), reflection responses, XP/badges/level data, community membership and posts, challenge history, account activity log.
Export formats: machine-readable (JSON), human-readable summary (PDF), media files (ZIP archive).
Timeline: acknowledged within 48 hours, delivered within 30 days (CCPA requirement). Self-service for simple exports; complex requests handled by support.
Right to Delete:
Deletion process:
- User requests deletion (Settings -> Delete Account)
- Confirmation required (re-authentication + typing "DELETE" + checkbox acknowledgment)
- 30-day grace period (account deactivated, not deleted)
- During grace period: user can reactivate by logging back in
- After grace period: permanent deletion executed
What gets deleted: profile data, Track Records and entries, media files, reflection responses, community posts (or anonymized at user option), XP/badges/achievements, parent-child links, session data.
What gets retained (anonymized): aggregate analytics contributions (no re-identification possible), audit log entries (user identity anonymized).
What gets retained (as-is): vendor-created challenge data, community metadata (member count adjustments), financial transaction records (7-year legal compliance).
COPPA-Specific Deletion:
- Parent requests for under-13 deletion must be processed within 48 hours (not 30 days)
- No grace period for COPPA deletion requests
Right to Rectification: Users can correct their own data via profile editing. Parents can request correction of child's data. School-context corrections go through SA. Track Record content corrections allowed before verification.
Right to Data Portability: Export in standard formats (JSON, CSV), media files in original format, structured data importable into other systems.
Cookie Policy
STATUS: BUILT
The CookieConsentBanner component is fully interactive with Accept All, Reject All, and Customize options. The useLegalStore (Zustand with localStorage persistence) manages consent status, preferences per category, consent timestamp, and banner visibility. The CookiePreferences type defines three categories: necessary (always true), analytics, and marketing. Consent state persists across sessions.
Three Cookie Categories:
| Cookie | Category | Duration | Purpose |
|---|---|---|---|
| Session | Strictly Necessary | 30 days | Authentication |
| CSRF | Strictly Necessary | Session | Security |
| Consent | Strictly Necessary | 1 year | Remember cookie preference |
| Preferences | Functional | 1 year | Display settings (language, locale, reduced motion) |
| Analytics | Analytics (requires consent) | 1 year | First-party page view and feature usage tracking |
Consent Rules:
- Banner on first visit for non-necessary cookies
- Options: accept all, reject non-necessary, or customize per category
- Consent stored in cookie (and persisted to localStorage via Zustand)
- Easy to change preferences later (link in footer)
- Under-13 users: no analytics cookies without parental consent
- No third-party advertising cookies
- No cross-site tracking cookies
Legal Documents Required
STATUS: BUILT
All nine required legal documents exist as viewable content pages in src/pages/public/: Privacy Policy, Terms of Service, Cookie Policy, Acceptable Use Policy, Community Guidelines, School Data Processing Agreement, DMCA Policy, Vendor Terms, and Accessibility Statement. Full legal document viewer with version history and acceptance tracking is implemented.
Nine legal documents must exist before launch:
| Document | Review Frequency | Key Contents |
|---|---|---|
| Terms of Service | Annually + major features | Eligibility, account terms, content ownership, minors, liability, disputes |
| Privacy Policy | Annually + data practice changes | Data collected, how used, sharing, children's privacy (COPPA section), rights, retention |
| Acceptable Use Policy | Semi-annually | Prohibited content (13 categories), prohibited behavior (8 categories), enforcement tiers |
| Community Guidelines | Semi-annually | Core values (encouraging, authentic, respectful, safe, original), minor-specific and vendor-specific guidelines |
| Cookie Policy | Annually | Cookie categories, consent mechanism, durations, third-party cookies |
| Vendor Terms & Agreement | Annually | Content ownership, data access limits, event liability, revenue terms, termination |
| School Data Processing Agreement | Annually | FERPA scope, school obligations, DoCurious obligations, sub-processors, state law compliance |
| DMCA / Copyright Policy | Annually | Designated agent, takedown process, counter-notification, repeat infringer policy (3 strikes) |
| Accessibility Statement | Quarterly | WCAG 2.1 AA target, current status, feedback mechanism, third-party content disclaimer |
Readability requirements: All documents written in plain English (target: 8th-grade reading level), key points highlighted or summarized at top, table of contents, effective date clearly stated, version history maintained.
Change notification requirements:
| Change Type | Notice Period | Method |
|---|---|---|
| Material Terms/Privacy change | 30 days | Email + in-app banner |
| Minor clarification/typo | Upon publication | Updated on website |
| DPA changes | 60 days | Email to SA + in-app |
| AUP/Community Guidelines update | 14 days | In-app notification |
| New policy document | Upon publication | Email to affected users |
Data Retention
STATUS: BUILT
Data retention automation is now implemented in compliance.service.ts with automated cleanup jobs: deleted accounts purged after 30 days, expired sessions cleaned after 90 days, and old reports archived after 180 days. Retention schedules are fully enforced programmatically.
| Data Type | Active Retention | After Account Deletion | Legal Hold |
|---|---|---|---|
| User profile | While account active | Deleted within 30 days | As required |
| Track Records | While account active | Deleted within 30 days | As required |
| Media files | While account active | Deleted within 30 days | As required |
| Reflection responses | While account active | Deleted within 30 days | As required |
| Audit logs | 2 years | Anonymized, retained 2 years | Retained |
| Parental consent records | While consent active + 3 years | Retained 3 years after deletion | Retained |
| School DPAs | Duration of contract + 5 years | Retained 5 years | Retained |
| Server logs | 90 days | N/A (anonymized) | As required |
| Analytics (aggregate) | Indefinite | N/A (no PII) | N/A |
| Backup data | Per backup schedule | Rolled out within 30 days | Retained |
Anonymization rules (when data is retained for analytics but user requests deletion):
- Replace
user_idwith random identifier - Remove all PII fields and all linking data (parent, school associations)
- Retain only aggregate-useful fields (completion counts, timestamps)
- Anonymization must be irreversible -- no re-identification possible
School contract termination:
- SA notified 30 days before data deletion
- SA can export all school data during this period
- After 30 days: all student records created in school context deleted
- Student personal accounts (non-school context) unaffected
- Confirmation of deletion sent to SA
Media & File Security
STATUS: PLANNED
Media security specifications are fully defined. The frontend supports file upload UI patterns, but backend file validation (magic byte checking, EXIF stripping, malware scanning, signed URL generation) is not yet implemented.
Upload Security:
- File type validated by magic bytes (not just extension)
- Maximum file size: 50MB per file (configurable)
- Allowed types: JPEG, PNG, GIF, WebP, MP4, MOV
- EXIF data stripped from images (GPS, device info) -- mandatory for under-18 users, default-on for all users
- Malware scanning (ClamAV or cloud service)
- Images re-encoded server-side (prevents image-based exploits)
Storage & Access:
- Files in cloud object storage (S3 or equivalent), not directly accessible via public URL
- Accessed through authenticated, signed URLs with expiration (1 hour for viewing, 15 minutes for upload)
- No directory listing, no guessable URLs
- Media inherits access permissions from parent resource (Track Record, profile, etc.)
Content Moderation:
- Automated image scanning for explicit content before publishing
- Hash-based matching against CSAM databases (NCMEC requirements)
- Immediate removal capability for confirmed violations
- Reporting to NCMEC as required by law
Sensitive Actions Requiring Re-Authentication
STATUS: BUILT
The spec defines eight categories of sensitive actions that require re-authentication. The AccountDeletion page requires typing "DELETE" and checking a confirmation box, but true re-authentication (password re-entry) is not yet enforced for any action.
The following actions require the user to re-enter their password before proceeding:
- Account deletion
- Email change
- Password change
- Adding or removing parent link
- Exporting personal data
- Admin impersonation
- Changing school COPPA settings
- Changing admin permissions
Roles & Permissions
Privacy-related permissions vary significantly by role:
| Action | User | Student | Parent | Teacher | SA | Platform Admin |
|---|---|---|---|---|---|---|
| View own data | Yes | Yes | Yes | Yes | Yes | Yes |
| Export own data | Yes | Yes | Yes | Yes | Yes | Yes |
| Delete own account | Yes | Yes | Yes | Yes | Yes | No (protected) |
| View child's data | -- | -- | Linked child | -- | -- | All |
| Delete child's data (COPPA) | -- | -- | Under-13 child | -- | -- | All |
| View student records | -- | Own only | Linked child | Own classes | All school | All |
| Export student records | -- | -- | Linked child | -- | All school | All |
| Request data rectification | Yes | Yes | For child | -- | For students | All |
| Manage cookie preferences | Yes | Yes | Yes | Yes | Yes | Yes |
| View audit logs | -- | -- | -- | -- | -- | Yes |
| Process DSAR requests | -- | -- | -- | -- | -- | Yes |
| Access parental consent records | -- | -- | Own records | -- | -- | System only |
| Configure school COPPA settings | -- | -- | -- | -- | Yes | Yes |
| Override data retention | -- | -- | -- | -- | -- | Yes |
Constraints & Limits
| Constraint | Value | Rationale |
|---|---|---|
| Password minimum length | 8 characters | NIST 800-63B recommendation |
| Password maximum length | 128 characters | Reasonable upper bound for bcrypt |
| Failed login lockout | 5 attempts / 15 min | Brute force protection |
| Progressive lockout ceiling | 1 hour after 15 failures | Prevents sustained attacks |
| Password reset rate limit | 3 per hour per email | Prevents abuse |
| API rate limit (authenticated) | 100 requests/min | Fair use enforcement |
| API rate limit (unauthenticated) | 20 requests/min | Abuse prevention |
| Session timeout | 30 days (with refresh) | Balances security and convenience |
| Session idle timeout | 7 days | Protects unattended sessions |
| Admin session timeout | 8 hours | Higher security for privileged accounts |
| Admin idle timeout | 1 hour | Minimizes admin session exposure |
| Max concurrent sessions | 5 (configurable) | Prevents credential sharing |
| Data export delivery | 30 days maximum | CCPA compliance requirement |
| Data export acknowledgment | 48 hours | Reasonable response time |
| Account deletion grace period | 30 days | Allows recovery from accidental deletion |
| COPPA deletion timeline | 48 hours | Stricter timeline for minor data |
| Parental consent record retention | 3 years after deletion | Compliance evidence |
| School DPA retention | 5 years after termination | Legal compliance |
| Audit log retention | 2 years (90 days hot) | Security and compliance |
| Server log retention | 90 days | Operational needs |
| Key rotation (Tier 1) | 90 days | High-security rotation schedule |
| Key rotation (other) | 1 year | Standard rotation |
| JWT access token expiry | 15 minutes | Short-lived for security |
| JWT refresh token expiry | 30 days | Matches session timeout |
| File upload max size | 50MB per file | Configurable, balances usability |
| Signed URL expiry (viewing) | 1 hour | Prevents link sharing abuse |
| Signed URL expiry (upload) | 15 minutes | Prevents stale upload tokens |
Design Decisions
Why four data tiers instead of two. Binary "sensitive / not sensitive" fails for a platform handling both COPPA-regulated minor data and public community posts. The four-tier system allows proportional security: Tier 1 data gets hardware-backed KMS encryption and 90-day key rotation, while Tier 4 public data gets standard protection. This avoids both under-protecting critical data and over-engineering public content.
Why column-level encryption for PII. Full-disk encryption protects against physical theft but not against a compromised database administrator. Column-level encryption on Tier 2 fields (emails, real names, dates of birth) means even DBAs with SELECT access see ciphertext. This is essential for COPPA and FERPA compliance where the spec requires that platform operators cannot casually browse user PII.
Why bcrypt/Argon2id with no complexity rules. NIST SP 800-63B recommends against character complexity rules (uppercase, special characters) because they reduce password space without improving security. Length is the dominant factor. DoCurious follows this by enforcing minimum 8 characters with HaveIBeenPwned breach checking rather than arbitrary complexity mandates.
Why 30-day grace period for account deletion. Immediate deletion is irreversible and creates support burden from accidental deletions. The 30-day deactivation window (during which the user can reactivate by logging back in) balances the right to deletion with protection against mistakes. Note that COPPA parent-initiated deletions for under-13 children skip this grace period and must process within 48 hours.
Why the school is the data controller under FERPA. DoCurious processes student education records on behalf of schools, not independently. This "school official with legitimate educational interest" model means schools retain control over their students' data, DoCurious acts only as instructed per the DPA, and parents exercise FERPA rights through the school (not through DoCurious directly). This is both legally required and operationally cleaner.
Why cookie consent uses three categories, not two. The spec distinguishes between strictly necessary (session, CSRF, consent preference), functional (language, display settings), and analytics cookies. Functional cookies could be grouped with necessary, but separating analytics into its own consent category follows GDPR best practice and gives users meaningful control over tracking without breaking core functionality.
Why no third-party advertising cookies -- ever. DoCurious explicitly prohibits advertising cookies, cross-site tracking, and data sharing with ad networks. This is a hard requirement for COPPA compliance (no behavioral advertising to children) and a trust differentiator for schools and parents. The platform monetizes through membership fees and vendor partnerships, not advertising.
What to revisit:
- Legal document content pages (all nine documents need to be written and viewable)
- Backend encryption implementation (column-level, KMS integration)
- MFA setup UI for admin users
- Re-authentication enforcement for sensitive actions
- Automated data retention cleanup jobs
- Breach notification workflow and incident response tooling
- FERPA parent inspection rights UI
- Annual COPPA consent renewal workflow
- Sub-processor list public page
Technical Implementation
Types
| Type | File | Description |
|---|---|---|
CookieConsentStatus | src/types/legal.types.ts | Consent status enum: pending | accepted | rejected | customized |
CookiePreferences | src/types/legal.types.ts | Three-category cookie preferences (necessary always true, analytics, marketing) |
ConsentStatus | src/types/user.types.ts | Parental consent lifecycle: not_required | pending | granted | revoked |
StudentAccountTier | src/types/user.types.ts | COPPA tier: tier_1_school_only | tier_2_parent_linked |
PrivacySettings | src/types/user.types.ts | User-controlled privacy: profileVisibility, showInPartnerFinder, showCommunityMemberships |
AuthTokens | src/types/auth.types.ts | JWT access/refresh token pair with expiry |
SessionInfo | src/types/auth.types.ts | Session details: userId, role, issuedAt, expiresAt, deviceInfo |
ParentConsentRequest | src/types/auth.types.ts | Request payload: childUserId, parentEmail |
ParentConsentConfirm | src/types/auth.types.ts | Confirmation: token, approved, sharingPermissions |
LoginAttempt | src/types/auth.types.ts | Rate limiting: email, attempts, lastAttempt, lockedUntil |
AuthErrorCode | src/types/auth.types.ts | Error codes including consent_required, account_locked, rate_limited |
ParentVerification | src/types/payment.types.ts | COPPA $1 credit card verification with Stripe integration |
ParentVerificationMethod | src/types/payment.types.ts | Verification method: credit_card_1dollar | knowledge_based |
ParentVerificationStatus | src/types/payment.types.ts | Status: pending | processing | verified | failed | refunded |
SASetupWizardData.coppaConfig | src/types/onboarding.types.ts | School COPPA configuration: enabled, age restriction, consent method |
Store
| Store | File | Description |
|---|---|---|
useLegalStore | src/store/useLegalStore.ts | Cookie consent management with Zustand + localStorage persistence. Actions: acceptAll, rejectAll, customizePreferences, dismissBanner, resetConsent. |
useAuthStore | src/store/useAuthStore.ts | Authentication state including isUnder13, needsConsent selectors, session management, and login/logout flows. |
Key selectors: selectConsentStatus, selectCookiePreferences, selectShowBanner (legal store); selectIsUnder13, selectNeedsConsent (auth store)
Route Guards
| Guard | File | Description |
|---|---|---|
AuthGuard | src/routes/guards/AuthGuard.tsx | Requires authentication. Redirects to /login with saved return location. Shows spinner during initialization. |
AgeGuard | src/routes/guards/AgeGuard.tsx | COPPA age gating. Blocks under-13 users from 13+ content. Configurable minAge prop (default: 13). Shows fallback or redirects. |
ConsentGuard | src/routes/guards/ConsentGuard.tsx | Parental consent enforcement. Blocks under-13 users without granted consent from Tier 2 features. Shows "Parent Permission Required" fallback. |
AdminRoleGuard | src/routes/guards/AdminRoleGuard.tsx | Restricts to admin roles. |
ParentGuard | src/routes/guards/ParentGuard.tsx | Restricts to parent role. |
TierGuard | src/routes/guards/TierGuard.tsx | Restricts based on student account tier. |
ContextGuard | src/routes/guards/ContextGuard.tsx | Restricts based on active context (school, vendor, etc.). |
Pages
| Page | File | Description |
|---|---|---|
AccountDeletion | src/pages/account/AccountDeletion.tsx | Account deletion with DELETE confirmation, understanding checkbox, 30-day grace period notice, and redirect to login. |
DataExportRequest | src/pages/account/DataExportRequest.tsx | Category-based data export (profile, Track Records, reflections, communities, messages) with size estimates, export history, and status tracking. |
DataAccessRequest | src/pages/account/DataAccessRequest.tsx | GDPR/CCPA DSAR form with four request types (Access, Correct, Restrict, Portability), conditional detail forms, identity verification notice, and request history. |
LinkedAccounts | src/pages/account/LinkedAccounts.tsx | Manage parent-child account links. |
AppealForm | src/pages/account/AppealForm.tsx | Account action appeal submission. |
Components
| Component | File | Description |
|---|---|---|
CookieConsentBanner | src/components/common/CookieConsentBanner.tsx | Fixed bottom banner with Accept All / Reject All / Customize. Customize view shows per-category toggles (Essential always on, Analytics, Marketing). Uses useLegalStore for state. |
FeatureGate | src/components/common/FeatureGate.tsx | Feature flag gate that can conditionally render based on feature flags (used for privacy feature rollouts). |
Data Models (Spec -- Not Yet in DB)
The spec defines five privacy-specific database tables:
| Table | Purpose |
|---|---|
parental_consent_records | COPPA consent tracking: parent/child IDs, method, timestamp, IP, policy version, scope, withdrawal |
data_requests | DSAR tracking: requestor, type (export/delete/rectification), target user, status, processing timestamps |
security_events | Security audit log: event type, severity, user, IP, resource, action, result, details |
third_party_dpas | Third-party data processing agreements: vendor, purpose, data shared, certifications, COPPA compliance |
school_dpas | School DPA tracking: organization, signed date, version, contract dates, deletion dates, status |
HTTP Security Headers (Spec)
Strict-Transport-Security: max-age=31536000; includeSubDomains
Content-Security-Policy: default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' blob: data: https://storage.example.com;
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
X-XSS-Protection: 0
Referrer-Policy: strict-origin-when-cross-origin
Permissions-Policy: camera=(), microphone=(), geolocation=()Security Monitoring Alerts (Spec)
| Alert | Trigger | Severity |
|---|---|---|
| Brute force attempt | 10+ failed logins for one account in 5 min | High |
| Credential stuffing | 50+ failed logins from one IP in 5 min | High |
| Privilege escalation attempt | User attempts admin endpoint | Critical |
| Data exfiltration | Unusual volume of data export requests | High |
| Admin abuse | Admin accesses unusual volume of user records | Medium |
| SQL injection attempt | Suspicious query patterns in WAF logs | High |
| CSAM detection | Image scanning match | Critical |
| Unusual API patterns | 10x normal request volume | Medium |
| Certificate expiry | Less than 14 days to expiry | Medium |
| Dependency vulnerability | Critical CVE in production dependency | High |
Related Features
- Accounts -- User types, COPPA two-tier system, account linkages, parent-child linking flow, consent management, age verification at registration
- School Administration -- FERPA context, school-as-controller model, roster management, COPPA tier enforcement in school workflows, school DPA
- Communities -- Privacy-scoped community visibility, minor-safe community rules, content moderation
- Track Records -- User-owned content, verification workflows, media uploads (EXIF stripping), sharing controls
- Notifications -- Parent consent notifications, breach notification channels, DSAR status updates
- Vendor -- Vendor data isolation (aggregate only, no individual user data), vendor terms, third-party DPA requirements
- Gamification -- XP/badge data included in exports and deletion, anti-manipulation rules