From 696d23dfad9399c222c2845d48c502fe065eb08a Mon Sep 17 00:00:00 2001 From: Josh Date: Wed, 15 Oct 2025 18:15:06 +0000 Subject: [PATCH] Updated pricing, financial disclaimer in retirement planner --- .build.hash | 2 +- .gitignore | 1 + .last-lock | 2 +- .lock.hash | 2 +- APTIVA_AI_FEATURES_DOCUMENTATION.md | 859 ++++++++++++++++++++++ backend/server2.js | 2 +- nginx.conf | 3 +- package-lock.json | 1043 ++++++++++++++++++++++++++- package.json | 22 +- src/components/Paywall.js | 88 ++- src/components/RetirementPlanner.js | 12 +- src/index.js | 15 +- 12 files changed, 2006 insertions(+), 45 deletions(-) create mode 100644 APTIVA_AI_FEATURES_DOCUMENTATION.md diff --git a/.build.hash b/.build.hash index cdab437..f2dad3a 100644 --- a/.build.hash +++ b/.build.hash @@ -1 +1 @@ -960faad1696b81c0f004065ea713edaef64ab816-372bcf506971f56c4911b429b9f5de5bc37ed008-e9eccd451b778829eb2f2c9752c670b707e1268b +506c4d11372627a92e39ee44d85a809d000a0840-006fe5ea7fd8cb46290bcd0cf210f88f2ec04061-e9eccd451b778829eb2f2c9752c670b707e1268b diff --git a/.gitignore b/.gitignore index c06cc91..b371a05 100644 --- a/.gitignore +++ b/.gitignore @@ -27,3 +27,4 @@ uploads/.env .env.* scan-env.sh .aptiva-test-user.json +APTIVA_AI_FEATURES_DOCUMENTATION.md diff --git a/.last-lock b/.last-lock index 99340a5..d0bbd95 100644 --- a/.last-lock +++ b/.last-lock @@ -1 +1 @@ -98f674eca26e366aee0b41f250978982060105f0 +ad5628b638213a971abbea4f95362eca8672be7b diff --git a/.lock.hash b/.lock.hash index 99340a5..d0bbd95 100644 --- a/.lock.hash +++ b/.lock.hash @@ -1 +1 @@ -98f674eca26e366aee0b41f250978982060105f0 +ad5628b638213a971abbea4f95362eca8672be7b diff --git a/APTIVA_AI_FEATURES_DOCUMENTATION.md b/APTIVA_AI_FEATURES_DOCUMENTATION.md new file mode 100644 index 0000000..1c4be34 --- /dev/null +++ b/APTIVA_AI_FEATURES_DOCUMENTATION.md @@ -0,0 +1,859 @@ +# AptivaAI Application - Comprehensive Feature Documentation + +**Date:** 2025-10-15 +**Purpose:** Marketing and content creation reference + +--- + +## OVERVIEW + +AptivaAI is a career guidance and financial planning platform that helps users discover careers, plan their education, enhance their career trajectory, and prepare for retirement. The platform uses AI-powered tools, O*NET career data, Bureau of Labor Statistics salary information, and financial projection algorithms. + +--- + +## TIER STRUCTURE + +### FREE TIER +Users without a premium subscription get access to: + +1. **Career Discovery Tools** + - Interest Inventory (60-question RIASEC assessment from O*NET) + - Career Explorer with career suggestions based on inventory results + - Career comparison tool with ratings across 6 dimensions (interests, meaning, stability, growth, balance, recognition) + - Career search functionality + - Access to 800+ career profiles with: + - Job descriptions and tasks (from O*NET) + - Regional and national salary data (from BLS) + - Economic projections by state and nationally + - AI automation risk assessment + - Job zone (education/preparation level) + - Educational pathways (CIP codes) + +2. **Educational Planning** + - Educational Programs search by career/CIP code + - School and program suggestions + - Distance calculations to schools + - Tuition cost estimates (using IPEDS data) + - Education loan repayment calculator + +3. **Account Management** + - User profile with location, contact info + - Email verification + - Password reset functionality + +4. **Support** + - Basic support chatbot (GPT-4o-mini powered) + - Support ticket system via email + +### PREMIUM TIER ($4.99/month or $49/year) + +All FREE features PLUS: + +1. **AI Career Coach** + - GPT-4o powered conversational career planning assistant + - Personalized milestone recommendations + - Context-aware advice based on your career profile + +2. **Career Roadmap & Planning** + - Create multiple career scenarios + - Track milestones with dates, descriptions, and tasks + - Financial impact modeling for milestones (salary changes, expense changes) + - Visual timeline with milestone markers + - Milestone completion tracking + +3. **Financial Projections** + - 20+ year financial simulations + - Tracks emergency savings, retirement savings, total savings, loan balances + - Monthly granularity projections + - Salary growth modeling + - Expense tracking and planning + - Debt payment modeling + - College cost integration (tuition, financial aid) + - Student loan amortization and payoff tracking + - Surplus allocation strategies (emergency vs retirement) + +4. **Career & College Profiles** + - Multiple career profile management + - College/education profile tracking per career + - Scenario comparison tools + +5. **Resume Optimization** + - **2 resume optimizations per week** + - Upload PDF or DOCX resume + - AI-powered resume rewriting tailored to specific job descriptions + - Uses GPT-4o + +6. **Premium Onboarding** + - Guided setup wizard for career and college profiles + - School selection with program matching + +### PRO PREMIUM TIER ($7.99/month or $79/year) + +All PREMIUM features PLUS: + +1. **Enhanced AI Access** + - Priority GPT-4o usage + - Higher rate limits on AI features + +2. **More Resume Optimizations** + - **5 resume optimizations per week** (vs 2 in regular Premium) + +### RETIREMENT PLANNER (Beta - Premium Feature) + +1. **Scenario Comparison** + - Create and compare up to 2 retirement scenarios side-by-side + - Clone scenarios for what-if analysis + - Edit scenario assumptions independently + +2. **Retirement Projections** + - Uses same financial projection engine as Career Roadmap + - Tracks retirement savings growth over time + - Models different contribution strategies + - Shows loan payoff timelines + - Adjustable simulation length + +3. **AI Retirement Advisor** (Beta) + - Conversational retirement planning assistant + - Can suggest scenario modifications + - Provides retirement strategy advice + +--- + +## KEY FUNCTIONALITY BREAKDOWN + +### Career Explorer + +**Purpose:** Help users discover and compare careers based on their interests and priorities. + +**How It Works:** +1. User completes 60-question Interest Inventory (RIASEC model) +2. System queries O*NET API with answers +3. Filters results to higher-education careers only +4. Enriches each career with: + - Job zone (preparation level 1-5) + - CIP codes (educational program codes) + - Economic projections (state and national) + - Salary data (percentiles 10/25/50/75/90) + - "Limited data" flag if key info is missing +5. Displays careers sorted by "fit" (Best/Great/Good) +6. Users can filter by job zone and fit level +7. Users add careers to comparison matrix +8. Comparison calculates weighted match score based on user's stated priorities + +**Career Priorities:** +Users weight importance of 6 factors: +- Interests (based on inventory) +- Meaning/purpose +- Job stability +- Career growth potential +- Work-life balance +- Recognition/advancement + +**Match Score Calculation:** +- Each career gets 1-5 rating in each dimension +- User priorities (Very important=5, Somewhat=3, Not as=1) +- Weighted average produces 0-100% match score + +### Career Roadmap + +**Purpose:** Plan and visualize career progression with financial impact. + +**How It Works:** +1. Users create career scenarios (one per target career) +2. Each scenario has: + - Career name, start date, status (planned/active/completed) + - Expected salary progression + - Monthly expense assumptions + - Debt payment plans + - Retirement/emergency contribution goals + - College enrollment status and details +3. Users add milestones to timeline: + - Promotion + - Relocation + - Degree completion + - Career change + - Major purchase + - Each with date, description, tasks +4. Milestones can have financial impacts: + - Salary change (absolute or %) + - Expense change (absolute or %) + - One-time costs +5. Financial simulator projects month-by-month: + - Emergency fund balance + - Retirement savings balance + - Total savings + - Student loan balance (if applicable) + - Net monthly savings +6. Chart displays projections with milestone markers +7. Loan payoff date shown if applicable + +**Financial Projection Engine:** +- Starts with current financial situation +- Models monthly cash flow: income - expenses - debt - contributions +- Applies surplus allocation rules (% to emergency vs retirement) +- Processes milestone impacts at specified dates +- Handles college costs during enrollment periods +- Models student loan interest and payments +- Supports loan deferral during school +- Projects growth (flat rate, random, or none) +- Auto-extends simulation horizon to cover furthest milestone + +### Interest Inventory + +**Purpose:** Assess user interests using validated RIASEC model. + +**What It Assesses:** +60 work activities scored on 5-point scale (Strongly Dislike to Strongly Like) + +**Output:** +- RIASEC scores across 6 dimensions: + - Realistic (hands-on, practical work) + - Investigative (analytical, research) + - Artistic (creative, expressive) + - Social (helping, teaching) + - Enterprising (leading, persuading) + - Conventional (organizing, clerical) +- Used to match careers via O*NET scoring +- Stored in user profile for ongoing use + +### Retirement Planner + +**Purpose:** Model different retirement scenarios and financial outcomes. + +**How It Works:** +1. Uses same financial profile as Career Roadmap +2. Creates separate scenarios with different assumptions: + - Retirement age + - Contribution amounts + - Expense levels + - Additional income sources +3. Projects savings growth to retirement +4. Compares scenarios side-by-side +5. Shows which scenario reaches retirement goals + +### Resume Optimizer + +**Purpose:** Tailor resumes to specific job postings using AI. + +**How It Works:** +1. User uploads resume (PDF or DOCX, max 5MB) +2. System extracts text using pdf-parse or mammoth +3. User provides job title and job description +4. GPT-4o analyzes resume against job requirements +5. AI rewrites resume to: + - Highlight relevant experience + - Match keywords from job description + - Optimize for ATS (Applicant Tracking Systems) + - Maintain truthfulness (no fabrication) +6. Returns optimized resume text +7. Rate-limited: 2/week (Premium) or 5/week (Pro) + +--- + +## DATA SOURCES + +### Career Database - COMPETITIVE ADVANTAGE ✨ +**Primary Source:** Bureau of Labor Statistics Standard Occupational Classification (SOC) system +**Coverage:** Complete BLS SOC database - THE federal standard for career classification (824 unique careers, filtered to professional/higher-education careers from full SOC) +**Unique Positioning:** No competing U.S. career database is larger - SOC is the authoritative source that all other systems (O*NET, Career OneStop, etc.) derive from +**Data Enhancement:** O*NET data used to enrich career listings with: +- Interest Inventory questions and scoring (RIASEC model) +- Detailed career descriptions and tasks +- Skills requirements +- Job zones (education/preparation levels) +**Note:** Not all careers have associated CIP codes for educational pathways + +**MARKETING LANGUAGE TO USE:** +- "800+ professional careers - the most comprehensive government career database" +- "Complete career database from the U.S. Bureau of Labor Statistics" +- "Based on the federal standard for career classification" +- "Every professional career tracked by the U.S. government" +- "Access to the SOURCE career data, not a derivative or subset" + +### Bureau of Labor Statistics (BLS) +**Source:** U.S. Department of Labor +**Usage:** +- Salary data (percentiles 10/25/50/75/90) +- Regional salary breakdowns +- National salary benchmarks +**Storage:** Local SQLite database (salary_info.db) +**Coverage:** SOC code based, regional (by area) and national + +### Economic Projections +**Source:** State labor market information agencies +**Usage:** +- Employment growth projections +- Base year and projected year job counts +- Annual openings estimates +**Storage:** Local JSON file (economicproj.json) +**Coverage:** State-level and national projections by SOC code + +### College/Education Database +**Primary:** Classification of Instructional Programs (CIP) codes from IPEDS (Integrated Postsecondary Education Data System) +**Coverage:** Complete CIP code listing - comprehensive educational programs database +**Includes:** +- Tuition costs (in-state, out-of-state, in-district) +- Program types and credentials +- Institution information +- CIP to SOC career pathway mappings + +### Google Maps API +**Usage:** +- Geocoding user ZIP codes +- Calculating distances to schools +- Provides driving distance and duration +**Access:** Live API calls (requires API key) + +### AI Services +**INTERNAL USE ONLY - DO NOT SHARE IN MARKETING** +**Provider:** OpenAI +**Models:** GPT-4o, GPT-4o-mini +**Usage:** Career coaching, resume optimization, support chatbot +**Marketing Language:** "AI-powered career coach", "powered by advanced AI", "intelligent career guidance" + +### Stripe +**Usage:** +- Payment processing for Premium/Pro subscriptions +- Checkout sessions +- Customer portal +- Webhook handling for subscription events +**Features:** +- Monthly and annual billing +- Subscription management +- Cancellation handling + +--- + +## LIMITATIONS (What AptivaAI Does NOT Do) + +### Career Discovery +- Does NOT guarantee job placement +- Does NOT provide direct connections to employers +- Does NOT include jobs requiring only high school education or less (filtered out) +- Covers all careers in BLS SOC database (1000+ careers) +- Does NOT provide real-time job market data (projections are historical) +- Does NOT assess personality beyond work interests +- Does NOT provide aptitude/skills testing beyond self-reported interests + +### Financial Planning +- Does NOT provide SEC-registered investment advice +- Does NOT connect to bank accounts or investment accounts +- Does NOT automatically track actual spending or income +- DOES model federal and state taxes (single filer, standard deduction, 2023 brackets) +- Does NOT include FICA (Social Security/Medicare taxes) +- Does NOT model local/city taxes, itemized deductions, credits, AMT, capital gains +- Does NOT account for inflation automatically (can be modeled via milestones) +- Does NOT model complex investment returns (flat rate or random range only) +- Social Security benefits modeling: PLANNED FEATURE (coming to Retirement Planner) +- Does NOT model pension plans +- Does NOT model early withdrawal penalties or RMD rules +- Does NOT provide insurance recommendations +- **IMPORTANT:** All projections are simulations based on assumptions - actual results will vary + +### Education Planning +- Does NOT apply to schools on user's behalf +- Does NOT guarantee admission or financial aid +- Does NOT provide official FAFSA guidance +- Does NOT track application deadlines +- Does NOT verify program accreditation +- Does NOT guarantee tuition accuracy (uses historical IPEDS data) +- Does NOT model scholarship or grant opportunities beyond user input + +### Resume Services +- Does NOT write resumes from scratch +- Does NOT fabricate experience or qualifications +- Does NOT guarantee interview callbacks +- Does NOT provide cover letter writing +- Does NOT submit applications on user's behalf +- Rate limited: NOT unlimited optimizations +- Does NOT support formats other than PDF and DOCX + +### AI Features +- Does NOT replace human judgment +- Does NOT guarantee accuracy of advice +- Rate-limited: NOT unlimited queries +- Does NOT provide real-time web search +- Does NOT store comprehensive conversation history +- AI can hallucinate or provide incorrect information +- Does NOT have access to user's email, calendar, or external accounts + +### Retirement Planning +- Does NOT provide fiduciary financial advice +- Does NOT recommend specific investments or funds +- Does NOT model complex retirement accounts (401k matching, Roth conversions, etc.) +- Does NOT account for healthcare costs in retirement +- Does NOT model Medicare or long-term care insurance +- Does NOT provide estate planning advice +- Social Security benefits: PLANNED FEATURE (in development) +- Currently in BETA - features may change + +### Data & Privacy +- Does NOT sell user data to third parties +- Does NOT share career information with employers without permission +- Does NOT verify employment status +- Does NOT perform background checks +- User data encrypted at rest in production + +### Integration +- Does NOT integrate with LinkedIn +- Does NOT integrate with Indeed, Glassdoor, or other job sites +- Does NOT integrate with educational institution application systems +- Does NOT sync with calendar apps +- Does NOT have mobile apps (web-only) + +--- + +## TECHNICAL ARCHITECTURE NOTES + +### Frontend +- React 18.2 +- React Router for navigation +- Chart.js for financial visualizations +- Tailwind CSS for styling +- Axios for API calls + +### Backend +- Node.js with Express +- Three separate servers (server1: auth/user, server2: career data, server3: premium features) +- MySQL database (production) +- SQLite databases (salary data, some local dev) +- Encrypted data at rest (Google Cloud KMS) +- Cookie-based session authentication (HttpOnly, Secure) +- Rate limiting on AI endpoints + +### Security +- Helmet for security headers +- CORS with strict origin allowlist +- Input validation and sanitization +- HPP (HTTP Parameter Pollution) protection +- No credentials in client-side code +- Encrypted database fields for sensitive data +- Request logging and audit trails + +--- + +## KEY USER FLOWS + +### New User Onboarding (Free) +1. Sign up with email/password +2. Email verification required +3. Complete user profile (location, contact info) +4. Optional: Complete Interest Inventory +5. Access Career Explorer and free tools + +### Premium Upgrade Flow +1. Click "Upgrade to Premium" CTA +2. Choose Premium ($4.99/mo) or Pro Premium ($7.99/mo) +3. Stripe checkout (monthly or annual billing) +4. Immediate access to premium features +5. Optional: Complete Premium Onboarding wizard + +### Premium Onboarding (First Career Roadmap) +1. Select or search for target career +2. System pre-fills career data (salary, projections) +3. Optional: Select school and program +4. System calculates tuition and program details +5. Review and confirm +6. Creates first career scenario +7. Redirects to Career Roadmap + +### Career Planning (Premium) +1. Navigate to Career Roadmap +2. Edit scenario details (salary, expenses, contributions) +3. Add milestones with dates and financial impacts +4. View financial projection chart +5. Ask AI Career Coach for milestone suggestions +6. Adjust and refine plan +7. Track progress over time + +### Resume Optimization (Premium) +1. Navigate to Resume Optimizer +2. Upload resume file (PDF/DOCX) +3. Enter job title and paste job description +4. Submit for optimization +5. View optimized resume text +6. Copy or download (user must manually save) +7. Limited to 2/week (Premium) or 5/week (Pro) + +--- + +## DISCLAIMERS USED IN THE APP + +### Financial Disclaimer (displayed on projection pages): +"This financial projection is for educational and planning purposes only and should not be considered professional financial advice. Projections are based on assumptions you provide and historical data. Actual results will vary based on market conditions, individual circumstances, and unforeseeable events. AptivaAI is not a registered investment advisor. Consult with a qualified financial professional before making investment decisions." + +### AI Coach Disclaimer: +"AI-generated suggestions are for informational purposes only and may not be accurate or suitable for your specific situation. Always verify information independently and consult qualified professionals for important decisions." + +### Salary Data: +"Salary data sourced from the Bureau of Labor Statistics and may not reflect current market conditions in all areas." + +--- + +## SUBSCRIPTION MANAGEMENT + +### Premium Subscription +- **Price:** $4.99/month or $49/year +- **Billing:** Automated via Stripe +- **Cancellation:** Anytime via Stripe customer portal +- **Access:** Immediate upon payment +- **Renewal:** Auto-renews unless cancelled +- **Refunds:** Handled via Stripe refund policies + +### Pro Premium Subscription +- **Price:** $7.99/month or $79/year +- **Same billing/cancellation as Premium** +- **Upgrade:** Can upgrade from Premium anytime +- **Downgrade:** Can downgrade to Premium + +### Feature Access Control +- Frontend: Routes wrapped in `` component +- Backend: Endpoints check `is_premium` or `is_pro_premium` flags +- Resume limit enforcement: Tracks usage in database per user per week + +--- + +## SUPPORT & HELP + +### Free Users +- AI chatbot (GPT-4o-mini) for basic questions +- Rate-limited support ticket system +- Documentation via in-app info tooltips +- No direct human support + +### Premium Users +- Same AI chatbot +- Higher rate limits on support tickets +- Priority consideration (implied) +- Dedicated career coach AI for career questions + +### Support Ticket System +- Email-based (via SendGrid) +- Categories: general, billing, technical, data, UX +- Rate limits: 1 per 30 seconds, 3 per day per user +- Deduplication prevents spam +- Replies go to user's email on file + +--- + +## DATA ACCURACY & FRESHNESS + +### Career Data (O*NET) +- Updated: Periodically by O*NET Center +- AptivaAI: Live API calls get latest O*NET data +- Lag: Minimal (real-time from O*NET) + +### Salary Data (BLS) +- Updated: Annually by BLS (May survey data) +- AptivaAI: Database updated manually when new BLS data released +- Lag: 6-12 months behind current year + +### Economic Projections +- Updated: Every 2 years by state agencies +- AptivaAI: JSON file updated when new projections available +- Lag: Up to 2 years + +### College/Tuition Data (IPEDS) +- Updated: Annually by NCES +- AptivaAI: Datasets updated manually when new IPEDS data released +- Lag: 1-2 years + +### AI Models +- GPT-4o: Knowledge cutoff per OpenAI (typically ~6 months behind) +- GPT-4o-mini: Same limitations +- Does NOT have real-time web access + +--- + +## MOBILE SUPPORT + +- Responsive web design +- Works on mobile browsers (iOS Safari, Android Chrome) +- Touch-friendly interface +- Mobile navigation drawer +- Charts optimized for mobile viewing +- NO native mobile apps (iOS/Android) + +--- + +## BROWSER SUPPORT + +### Supported Browsers +- Chrome (last 2 versions) +- Firefox (last 2 versions) +- Safari (last 2 versions) +- Edge (last 2 versions) + +### Not Officially Supported +- Internet Explorer +- Opera Mini +- Older mobile browsers + +--- + +## ACCESSIBILITY + +- Semantic HTML structure +- Keyboard navigation support +- ARIA labels on interactive elements +- Focus indicators +- Color contrast meets WCAG AA guidelines (in most areas) +- No formal WCAG audit conducted +- Screen reader support: partial + +--- + +## PERFORMANCE + +### Data Loading +- Career suggestions: 30-60 seconds (parallel API calls to O*NET, BLS, projections) +- Resume optimization: 10-30 seconds (depends on OpenAI response time) +- AI chat responses: 5-15 seconds streaming +- Financial projections: Instant (client-side calculation) + +### Caching +- Career suggestions cached in localStorage +- Salary queries cached in memory (server-side, 512 entries) +- O*NET descriptions cached in database after first fetch + +### Rate Limits +- Resume optimization: 2-5 per week per user +- AI chat: 20 messages per hour per user +- Support tickets: 3 per day per user +- Interest Inventory submissions: No hard limit (but typically once) + +--- + +## FUTURE LIMITATIONS (Not Currently Built) + +These are things users might expect but are NOT available: + +1. Job application tracking +2. Interview preparation tools +3. Networking features +4. Mentorship matching +5. Certification tracking +6. Skills gap analysis (beyond career-to-education mapping) +7. Salary negotiation guidance +8. Performance review tracking +9. Professional development plan templates +10. Team/org features (currently individual-only) +11. Export to Excel/PDF (charts and reports) +12. Calendar integration +13. Email reminders for milestones +14. Mobile push notifications +15. Social sharing features +16. Public profiles or career pages +17. API access for third-party integrations +18. Bulk user management (for schools/organizations) + +--- + +## COMPETITIVE POSITIONING + +### What Makes AptivaAI Different + +**vs. LinkedIn:** +- More detailed career planning and financial modeling +- Evidence-based interest assessment (O*NET RIASEC) +- No job listings or networking features +- Focused on planning, not job searching + +**vs. Career Counselors:** +- 24/7 availability +- AI-powered suggestions +- Detailed financial projections +- Much lower cost +- But lacks human judgment and personalization + +**vs. Financial Advisors:** +- Focused on career-related financial decisions +- Integrated career and financial planning +- Lower cost +- But not SEC-registered, no fiduciary duty + +**vs. O*NET OnLine (free government site):** +- Easier interface +- Financial planning integration +- AI-powered career coach +- Milestone tracking +- But O*NET OnLine is free and comprehensive + +**vs. MyNextMove (O*NET consumer site):** +- Similar interest inventory +- More detailed financial planning +- Premium AI features +- But MyNextMove is free + +--- + +## IDEAL USER PROFILES + +### High School Students (Free tier) +- Discovering career options +- Taking interest inventory +- Researching education requirements +- Exploring salary potential + +### College Students (Free or Premium) +- Confirming career choice +- Finding relevant programs +- Planning finances with student loans +- Estimating post-grad salary + +### Career Changers (Premium recommended) +- Exploring new career paths +- Financial modeling for career transition +- Education/reskilling planning +- Milestone tracking for transition + +### Early Career Professionals (Premium recommended) +- Career advancement planning +- Financial goal setting +- Resume optimization for promotions +- Long-term career trajectory + +### Mid-Career Professionals (Premium/Pro) +- Retirement planning +- Multiple scenario comparison +- Career pivot exploration +- Executive advancement planning + +--- + +## MARKETING KEY POINTS + +### Value Propositions + +**For Free Users:** +- "Discover your ideal career path with science-backed interest assessment" +- "Compare careers side-by-side with real salary and growth data" +- "Find schools and programs that match your career goals" +- "Free career guidance powered by government labor data" + +**For Premium Users:** +- "Plan your entire career trajectory with AI-powered insights" +- "See exactly how career decisions impact your financial future" +- "Get personalized milestone recommendations from your AI career coach" +- "Optimize your resume for any job in minutes" +- "Only $4.99/month - less than a cup of coffee per week" + +**For Pro Premium Users:** +- "Unlock unlimited access to GPT-4o career coaching" +- "Optimize up to 5 resumes per week" +- "Priority AI response times" +- "Advanced retirement planning tools" + +### Unique Selling Points + +1. **Evidence-Based:** Uses validated O*NET RIASEC model and official government data +2. **Integrated:** Career + Education + Financial planning in one platform +3. **AI-Powered:** GPT-4o career coach provides personalized guidance +4. **Transparent:** Real salary data from BLS, economic projections from state agencies +5. **Affordable:** Premium features at less than $5/month +6. **Visual:** Interactive charts show financial impact of career decisions +7. **Flexible:** Model different scenarios and what-if situations +8. **Privacy-Focused:** No data selling, encrypted storage + +### Objections & Responses + +**"Why not just use O*NET for free?"** +→ AptivaAI adds financial planning, AI coaching, milestone tracking, and an integrated experience. O*NET is a reference tool; AptivaAI is a career management platform. + +**"How accurate are the salary projections?"** +→ Salary ranges come directly from BLS official data. Projections model YOUR specific situation based on assumptions you control. They're as accurate as any financial planning tool. + +**"Can't I plan my career in Excel?"** +→ You could, but AptivaAI does the heavy lifting: pulls in career data, calculates complex financial models, provides AI guidance, and visualizes everything beautifully. + +**"Why pay when LinkedIn is free?"** +→ LinkedIn is for networking and job hunting. AptivaAI is for career planning and financial modeling. Different tools for different purposes. + +**"Is this just another chatbot?"** +→ No, the AI coach is one feature among many. Core value is integrated career/education/financial planning with real government data. + +--- + +## TERMINOLOGY GUIDE + +**SOC Code:** Standard Occupational Classification code - government system for categorizing careers + +**CIP Code:** Classification of Instructional Programs code - categorizes educational programs + +**RIASEC:** Holland's theory of career choice (Realistic, Investigative, Artistic, Social, Enterprising, Conventional) + +**Job Zone:** O*NET's 1-5 scale for education/preparation needed + +**Milestone:** Career event or goal with a date and optional financial impact + +**Scenario:** A complete career plan including career choice, financial assumptions, and milestones + +**Financial Profile:** User's current financial situation (income, expenses, savings, debts) + +**Career Profile:** Details about a specific career path the user is considering or pursuing + +**College Profile:** Educational institution and program details associated with a career profile + +**Projection:** Month-by-month financial forecast based on scenario assumptions + +**O*NET:** Occupational Information Network - comprehensive database of occupational info + +**BLS:** Bureau of Labor Statistics - provides wage and employment data + +**IPEDS:** Integrated Postsecondary Education Data System - college/university data + +--- + +## LEGAL & COMPLIANCE + +### Licenses & Attributions +- O*NET data: CC BY 4.0 (attributed in Career Explorer) +- OpenAI: Commercial license (paid API usage) +- Stripe: Payment processor agreement +- Google Maps: Commercial license + +### Privacy +- Privacy Policy: https://aptivaai.com/privacy +- Terms of Service: https://aptivaai.com/terms +- Email verification required +- Encrypted data storage +- No data selling + +### Financial Disclaimers +- Not investment advice +- Not a registered investment advisor +- Projections are educational only +- Users should consult professionals + +### Trademark +- AptivaAI™ is a trademark of AptivaAI LLC +- O*NET® is a trademark of USDOL/ETA + +--- + +## CONCLUSION + +AptivaAI is a comprehensive career guidance platform that combines evidence-based career assessment, real government labor market data, financial modeling, and AI-powered coaching. The free tier provides robust career discovery tools, while Premium tiers add advanced planning, AI guidance, and resume optimization for under $5-8/month. + +**Core Strengths:** +- Integration of career, education, and financial planning +- Evidence-based (O*NET, BLS data) +- Affordable premium features +- AI-powered personalization + +**Key Limitations:** +- No job search or networking features +- No direct employer connections +- Financial projections are simulations, not guarantees +- AI can make mistakes +- Rate limits on premium features + +**Target Market:** +- Students exploring careers +- Early-career professionals planning advancement +- Career changers modeling transitions +- Mid-career professionals planning retirement + +--- + +*This document is for internal use only to guide marketing and content creation. Do not share publicly without review.* diff --git a/backend/server2.js b/backend/server2.js index 60a0001..2a2e412 100755 --- a/backend/server2.js +++ b/backend/server2.js @@ -1747,7 +1747,7 @@ app.post('/api/chat/threads', authenticateUser, async (req, res) => { ); // Seed a first assistant message so the drawer never appears blank const intro = - 'Hi — Aptiva Support here. I can help with CareerExplorer, account/billing, or technical issues. What do you need?'; + 'Hi — Aptiva Support here. I can help with how to use AptivaAI, account/billing, or technical issues. What do you need?'; await pool.query( 'INSERT INTO ai_chat_messages (thread_id,user_id,role,content) VALUES (?,?, "assistant", ?)', [id, userId, intro] diff --git a/nginx.conf b/nginx.conf index 2cdcd55..e961e7b 100644 --- a/nginx.conf +++ b/nginx.conf @@ -94,7 +94,8 @@ http { return 302 /signin$is_args$args; } location / { - try_files $uri $uri/ /index.html; + # First try the exact file, then directory with index.html, then directory/, then fallback + try_files $uri $uri/index.html $uri/ /index.html; } location ~* \.(?:ico|css|js|gif|jpe?g|png|woff2?|eot|ttf|svg)$ { expires 6M; diff --git a/package-lock.json b/package-lock.json index c5bf38e..1136320 100644 --- a/package-lock.json +++ b/package-lock.json @@ -83,6 +83,7 @@ "glob": "^11.0.3", "globals": "^16.3.0", "postcss": "^8.5.3", + "react-snap": "^1.23.0", "tailwindcss": "^3.4.17", "typescript-eslint": "^8.38.0" } @@ -5890,6 +5891,13 @@ "node": ">= 0.4" } }, + "node_modules/async-limiter": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz", + "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==", + "dev": true, + "license": "MIT" + }, "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", @@ -6534,6 +6542,16 @@ "ieee754": "^1.1.13" } }, + "node_modules/buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + } + }, "node_modules/buffer-equal-constant-time": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", @@ -6895,6 +6913,142 @@ "integrity": "sha512-+67P1GkJRaxQD6PKK0Et9DhwQB+vGg3PM5+aavopCpZT1lj9jeqfvpgTLAWErNj8qApkkmXlu/Ug74kmhagkXg==", "license": "MIT" }, + "node_modules/cheerio": { + "version": "1.0.0-rc.2", + "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.2.tgz", + "integrity": "sha512-9LDHQy1jHc/eXMzPN6/oah9Qba4CjdKECC7YYEE/2zge/tsGwt19NQp5NFdfd5Lx6TZlyC5SXNQkG41P9r6XDg==", + "dev": true, + "license": "MIT", + "dependencies": { + "css-select": "~1.2.0", + "dom-serializer": "~0.1.0", + "entities": "~1.1.1", + "htmlparser2": "^3.9.1", + "lodash": "^4.15.0", + "parse5": "^3.0.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cheerio/node_modules/css-select": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-1.2.0.tgz", + "integrity": "sha512-dUQOBoqdR7QwV90WysXPLXG5LO7nhYBgiWVfxF80DKPF8zx1t/pUd2FYy73emg3zrjtM6dzmYgbHKfV2rxiHQA==", + "dev": true, + "license": "BSD-like", + "dependencies": { + "boolbase": "~1.0.0", + "css-what": "2.1", + "domutils": "1.5.1", + "nth-check": "~1.0.1" + } + }, + "node_modules/cheerio/node_modules/css-what": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-2.1.3.tgz", + "integrity": "sha512-a+EPoD+uZiNfh+5fxw2nO9QwFa6nJe2Or35fGY6Ipw1R3R4AGz1d1TEZrCegvw2YTmZ0jXirGYlzxxpYSHwpEg==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": "*" + } + }, + "node_modules/cheerio/node_modules/dom-serializer": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.1.tgz", + "integrity": "sha512-l0IU0pPzLWSHBcieZbpOKgkIn3ts3vAh7ZuFyXNwJxJXk/c4Gwj9xaTJwIDVQCXawWD0qb3IzMGH5rglQaO0XA==", + "dev": true, + "license": "MIT", + "dependencies": { + "domelementtype": "^1.3.0", + "entities": "^1.1.1" + } + }, + "node_modules/cheerio/node_modules/domelementtype": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz", + "integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==", + "dev": true, + "license": "BSD-2-Clause" + }, + "node_modules/cheerio/node_modules/domhandler": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.4.2.tgz", + "integrity": "sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "domelementtype": "1" + } + }, + "node_modules/cheerio/node_modules/domutils": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.5.1.tgz", + "integrity": "sha512-gSu5Oi/I+3wDENBsOWBiRK1eoGxcywYSqg3rR960/+EfY0CF4EX1VPkgHOZ3WiS/Jg2DtliF6BhWcHlfpYUcGw==", + "dev": true, + "dependencies": { + "dom-serializer": "0", + "domelementtype": "1" + } + }, + "node_modules/cheerio/node_modules/entities": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz", + "integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==", + "dev": true, + "license": "BSD-2-Clause" + }, + "node_modules/cheerio/node_modules/htmlparser2": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.10.1.tgz", + "integrity": "sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "domelementtype": "^1.3.1", + "domhandler": "^2.3.0", + "domutils": "^1.5.1", + "entities": "^1.1.1", + "inherits": "^2.0.1", + "readable-stream": "^3.1.1" + } + }, + "node_modules/cheerio/node_modules/nth-check": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.2.tgz", + "integrity": "sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "boolbase": "~1.0.0" + } + }, + "node_modules/cheerio/node_modules/parse5": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-3.0.3.tgz", + "integrity": "sha512-rgO9Zg5LLLkfJF9E6CCmXlSE4UVceloys8JrFqCcHloC3usd/kJCyPDwH2SOlzix2j3xaP9sUX3e8+kvkuleAA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/cheerio/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/chokidar": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", @@ -8556,8 +8710,8 @@ "version": "0.1.13", "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", + "devOptional": true, "license": "MIT", - "optional": true, "dependencies": { "iconv-lite": "^0.6.2" } @@ -8809,6 +8963,23 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/es6-promise": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", + "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==", + "dev": true, + "license": "MIT" + }, + "node_modules/es6-promisify": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", + "integrity": "sha512-C+d6UdsYDk0lMebHNR4S2NybQMMngAOnOwYBQjTOiv0MkoJMP0Myw2mgpDLBcpfCmRLxyFqYhS/CfOENq4SJhQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "es6-promise": "^4.0.3" + } + }, "node_modules/escalade": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", @@ -9661,6 +9832,13 @@ "url": "https://opencollective.com/express" } }, + "node_modules/express-history-api-fallback": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/express-history-api-fallback/-/express-history-api-fallback-2.2.1.tgz", + "integrity": "sha512-swxwm3aP8vrOOvlzOdZvHlSZtJGwHKaY94J6AkrAgCTmcbko3IRwbkhLv2wKV1WeZhjxX58aLMpP3atDBnKuZg==", + "dev": true, + "license": "ISC" + }, "node_modules/express-rate-limit": { "version": "7.5.1", "resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-7.5.1.tgz", @@ -9721,6 +9899,39 @@ "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", "license": "MIT" }, + "node_modules/extract-zip": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-1.7.0.tgz", + "integrity": "sha512-xoh5G1W/PB0/27lXgMQyIhP5DSY/LhoCsOyZgb+6iMmRtCwVBo55uKaMoEYrDCKQhWvqEip5ZPKAc6eFNyf/MA==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "concat-stream": "^1.6.2", + "debug": "^2.6.9", + "mkdirp": "^0.5.4", + "yauzl": "^2.10.0" + }, + "bin": { + "extract-zip": "cli.js" + } + }, + "node_modules/extract-zip/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/extract-zip/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true, + "license": "MIT" + }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -9813,6 +10024,16 @@ "bser": "2.1.1" } }, + "node_modules/fd-slicer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", + "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "pend": "~1.2.0" + } + }, "node_modules/fetch-blob": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz", @@ -11139,6 +11360,16 @@ "node": ">=18.0.0" } }, + "node_modules/highland": { + "version": "2.13.0", + "resolved": "https://registry.npmjs.org/highland/-/highland-2.13.0.tgz", + "integrity": "sha512-zGZBcgAHPY2Zf9VG9S5IrlcC7CH9ELioXVtp9T5bU2a4fP2zIsA+Y8pV/n/h2lMwbWMHTX0I0xN0ODJ3Pd3aBQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "util-deprecate": "^1.0.2" + } + }, "node_modules/hoopy": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/hoopy/-/hoopy-0.1.4.tgz", @@ -11194,6 +11425,28 @@ "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", "license": "MIT" }, + "node_modules/html-minifier": { + "version": "3.5.21", + "resolved": "https://registry.npmjs.org/html-minifier/-/html-minifier-3.5.21.tgz", + "integrity": "sha512-LKUKwuJDhxNa3uf/LPR/KVjm/l3rBqtYeCOAekvG8F1vItxMUpueGd94i/asDDr8/1u7InxzFA5EeGjhhG5mMA==", + "dev": true, + "license": "MIT", + "dependencies": { + "camel-case": "3.0.x", + "clean-css": "4.2.x", + "commander": "2.17.x", + "he": "1.2.x", + "param-case": "2.1.x", + "relateurl": "0.2.x", + "uglify-js": "3.4.x" + }, + "bin": { + "html-minifier": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/html-minifier-terser": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", @@ -11215,6 +11468,74 @@ "node": ">=12" } }, + "node_modules/html-minifier/node_modules/camel-case": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-3.0.0.tgz", + "integrity": "sha512-+MbKztAYHXPr1jNTSKQF52VpcFjwY5RkR7fxksV8Doo4KAYc5Fl4UJRgthBbTmEx8C54DqahhbLJkDwjI3PI/w==", + "dev": true, + "license": "MIT", + "dependencies": { + "no-case": "^2.2.0", + "upper-case": "^1.1.1" + } + }, + "node_modules/html-minifier/node_modules/clean-css": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.2.4.tgz", + "integrity": "sha512-EJUDT7nDVFDvaQgAo2G/PJvxmp1o/c6iXLbswsBbUFXi1Nr+AjA2cKmfbKDMjMvzEe75g3P6JkaDDAKk96A85A==", + "dev": true, + "license": "MIT", + "dependencies": { + "source-map": "~0.6.0" + }, + "engines": { + "node": ">= 4.0" + } + }, + "node_modules/html-minifier/node_modules/commander": { + "version": "2.17.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.17.1.tgz", + "integrity": "sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg==", + "dev": true, + "license": "MIT" + }, + "node_modules/html-minifier/node_modules/lower-case": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-1.1.4.tgz", + "integrity": "sha512-2Fgx1Ycm599x+WGpIYwJOvsjmXFzTSc34IwDWALRA/8AopUKAVPwfJ+h5+f85BCp0PWmmJcWzEpxOpoXycMpdA==", + "dev": true, + "license": "MIT" + }, + "node_modules/html-minifier/node_modules/no-case": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/no-case/-/no-case-2.3.2.tgz", + "integrity": "sha512-rmTZ9kz+f3rCvK2TD1Ue/oZlns7OGoIWP4fc3llxxRXlOkHKoWPPWJOfFYpITabSow43QJbRIoHQXtt10VldyQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "lower-case": "^1.1.1" + } + }, + "node_modules/html-minifier/node_modules/param-case": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/param-case/-/param-case-2.1.1.tgz", + "integrity": "sha512-eQE845L6ot89sk2N8liD8HAuH4ca6Vvr7VWAWwt7+kvvG5aBcPmmphQ68JsEG2qa9n1TykS2DLeMt363AAH8/w==", + "dev": true, + "license": "MIT", + "dependencies": { + "no-case": "^2.2.0" + } + }, + "node_modules/html-minifier/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/html-webpack-plugin": { "version": "5.6.3", "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-5.6.3.tgz", @@ -12140,6 +12461,38 @@ "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", "license": "ISC" }, + "node_modules/isomorphic-fetch": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz", + "integrity": "sha512-9c4TNAKYXM5PRyVcwUZrF3W09nQ+sO7+jydgs4ZGW9dhsLG2VOlISJABombdQqQRXCwuYG3sYV/puGf5rp0qmA==", + "dev": true, + "license": "MIT", + "dependencies": { + "node-fetch": "^1.0.1", + "whatwg-fetch": ">=0.10.0" + } + }, + "node_modules/isomorphic-fetch/node_modules/is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/isomorphic-fetch/node_modules/node-fetch": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-1.7.3.tgz", + "integrity": "sha512-NhZ4CsKx7cYm2vSrBAr2PvFOe6sWDf0UYLRqA6svUYg7+/TSfVAu49jYC4BvQ4Sms9SZgdqGBgroqfDhJdTyKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "encoding": "^0.1.11", + "is-stream": "^1.0.1" + } + }, "node_modules/istanbul-lib-coverage": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", @@ -14166,6 +14519,92 @@ "mini-svg-data-uri": "cli.js" } }, + "node_modules/minimalcss": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/minimalcss/-/minimalcss-0.8.1.tgz", + "integrity": "sha512-a+kbRVvxz+oQf43pweflM38KvcvVuTvv3v6a8UgVbfS7E2rktSJSf8kfbGToSXgbiBDP83WTh8MWL6PdT9ljag==", + "dev": true, + "license": "MIT", + "dependencies": { + "cheerio": "1.0.0-rc.2", + "css-tree": "1.0.0-alpha.28", + "csso": "~3.5.0", + "filesize": "^3.5.11", + "minimist": "^1.2.0", + "puppeteer": "^1.8.0" + }, + "bin": { + "minimalcss": "bin/minimalcss.js" + } + }, + "node_modules/minimalcss/node_modules/css-tree": { + "version": "1.0.0-alpha.28", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.0.0-alpha.28.tgz", + "integrity": "sha512-joNNW1gCp3qFFzj4St6zk+Wh/NBv0vM5YbEreZk0SD4S23S+1xBKb6cLDg2uj4P4k/GUMlIm6cKIDqIG+vdt0w==", + "dev": true, + "license": "MIT", + "dependencies": { + "mdn-data": "~1.1.0", + "source-map": "^0.5.3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/minimalcss/node_modules/csso": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/csso/-/csso-3.5.1.tgz", + "integrity": "sha512-vrqULLffYU1Q2tLdJvaCYbONStnfkfimRxXNaGjxMldI0C7JPBC4rB1RyjhfdZ4m1frm8pM9uRPKH3d2knZ8gg==", + "dev": true, + "license": "MIT", + "dependencies": { + "css-tree": "1.0.0-alpha.29" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/minimalcss/node_modules/csso/node_modules/css-tree": { + "version": "1.0.0-alpha.29", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.0.0-alpha.29.tgz", + "integrity": "sha512-sRNb1XydwkW9IOci6iB2xmy8IGCj6r/fr+JWitvJ2JxQRPzN3T4AGGVWCMlVmVwM1gtgALJRmGIlWv5ppnGGkg==", + "dev": true, + "license": "MIT", + "dependencies": { + "mdn-data": "~1.1.0", + "source-map": "^0.5.3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/minimalcss/node_modules/filesize": { + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/filesize/-/filesize-3.6.1.tgz", + "integrity": "sha512-7KjR1vv6qnicaPMi1iiTcI85CyYwRO/PSFCu6SvqL8jN2Wjt/NIYQTFtFs7fSDCYOstUkEWIQGFUg5YZQfjlcg==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/minimalcss/node_modules/mdn-data": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-1.1.4.tgz", + "integrity": "sha512-FSYbp3lyKjyj3E7fMl6rYvUdX0FBXaluGqlFoYESWQlyUTq8R+wp0rkFxoYFqZlHCvsUXGjyJmLQSnXToYhOSA==", + "dev": true, + "license": "MPL-2.0" + }, + "node_modules/minimalcss/node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/minimalistic-assert": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", @@ -15380,6 +15819,13 @@ "path2d-polyfill": "^2.0.1" } }, + "node_modules/pend": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", + "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", + "dev": true, + "license": "MIT" + }, "node_modules/performance-now": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", @@ -17043,6 +17489,16 @@ "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", "license": "MIT" }, + "node_modules/progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/promise": { "version": "8.3.0", "resolved": "https://registry.npmjs.org/promise/-/promise-8.3.0.tgz", @@ -17192,6 +17648,124 @@ "node": ">=6" } }, + "node_modules/puppeteer": { + "version": "1.20.0", + "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-1.20.0.tgz", + "integrity": "sha512-bt48RDBy2eIwZPrkgbcwHtb51mj2nKvHOPMaSH2IsWiv7lOG9k9zhaRzpDZafrk05ajMc3cu+lSQYYOfH2DkVQ==", + "deprecated": "< 24.15.0 is no longer supported", + "dev": true, + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "debug": "^4.1.0", + "extract-zip": "^1.6.6", + "https-proxy-agent": "^2.2.1", + "mime": "^2.0.3", + "progress": "^2.0.1", + "proxy-from-env": "^1.0.0", + "rimraf": "^2.6.1", + "ws": "^6.1.0" + }, + "engines": { + "node": ">=6.4.0" + } + }, + "node_modules/puppeteer/node_modules/agent-base": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.3.0.tgz", + "integrity": "sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==", + "dev": true, + "license": "MIT", + "dependencies": { + "es6-promisify": "^5.0.0" + }, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/puppeteer/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/puppeteer/node_modules/https-proxy-agent": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz", + "integrity": "sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^4.3.0", + "debug": "^3.1.0" + }, + "engines": { + "node": ">= 4.5.0" + } + }, + "node_modules/puppeteer/node_modules/https-proxy-agent/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/puppeteer/node_modules/mime": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", + "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", + "dev": true, + "license": "MIT", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/puppeteer/node_modules/rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/puppeteer/node_modules/ws": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-6.2.3.tgz", + "integrity": "sha512-jmTjYU0j60B+vHey6TfR3Z7RD61z/hmxBS3VMSGIrroOWXQEneK1zNuotOUrGyBHQj0yrpsLHPWtigEFd13ndA==", + "dev": true, + "license": "MIT", + "dependencies": { + "async-limiter": "~1.0.0" + } + }, "node_modules/q": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", @@ -17713,6 +18287,396 @@ "node": ">=10" } }, + "node_modules/react-snap": { + "version": "1.23.0", + "resolved": "https://registry.npmjs.org/react-snap/-/react-snap-1.23.0.tgz", + "integrity": "sha512-spmg2maHSedLrn6QBAfLJkyMqeeffLTIs7h40pS1copW2xBrajx4HEAcanm+7IVGO6SYCPoGwvbU3U30UFN25g==", + "dev": true, + "license": "MIT", + "dependencies": { + "clean-css": "4.2.1", + "express": "4.16.4", + "express-history-api-fallback": "2.2.1", + "highland": "2.13.0", + "html-minifier": "3.5.21", + "minimalcss": "0.8.1", + "mkdirp": "0.5.1", + "puppeteer": "^1.8.0", + "serve-static": "1.13.2", + "sourcemapped-stacktrace-node": "2.1.8" + }, + "bin": { + "react-snap": "run.js" + }, + "engines": { + "node": ">= 8.6.0" + } + }, + "node_modules/react-snap/node_modules/body-parser": { + "version": "1.18.3", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.18.3.tgz", + "integrity": "sha512-YQyoqQG3sO8iCmf8+hyVpgHHOv0/hCEFiS4zTGUwTA1HjAFX66wRcNQrVCeJq9pgESMRvUAOvSil5MJlmccuKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "bytes": "3.0.0", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "~1.1.2", + "http-errors": "~1.6.3", + "iconv-lite": "0.4.23", + "on-finished": "~2.3.0", + "qs": "6.5.2", + "raw-body": "2.3.3", + "type-is": "~1.6.16" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/react-snap/node_modules/bytes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "integrity": "sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/react-snap/node_modules/clean-css": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.2.1.tgz", + "integrity": "sha512-4ZxI6dy4lrY6FHzfiy1aEOXgu4LIsW2MhwG0VBKdcoGoH/XLFgaHSdLTGr4O8Be6A8r3MOphEiI8Gc1n0ecf3g==", + "dev": true, + "license": "MIT", + "dependencies": { + "source-map": "~0.6.0" + }, + "engines": { + "node": ">= 4.0" + } + }, + "node_modules/react-snap/node_modules/content-disposition": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz", + "integrity": "sha512-kRGRZw3bLlFISDBgwTSA1TMBFN6J6GWDeubmDE3AF+3+yXL8hTWv8r5rkLbqYXY4RjPk/EzHnClI3zQf1cFmHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/react-snap/node_modules/cookie": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz", + "integrity": "sha512-+IJOX0OqlHCszo2mBUq+SrEbCj6w7Kpffqx60zYbPTFaO4+yYgRjHwcZNpWvaTylDHaV7PPmBHzSecZiMhtPgw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/react-snap/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/react-snap/node_modules/depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/react-snap/node_modules/destroy": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", + "integrity": "sha512-3NdhDuEXnfun/z7x9GOElY49LoqVHoGScmOKwmxhsS8N5Y+Z8KyPPDnaSzqWgYt/ji4mqwfTS34Htrk0zPIXVg==", + "dev": true, + "license": "MIT" + }, + "node_modules/react-snap/node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/react-snap/node_modules/express": { + "version": "4.16.4", + "resolved": "https://registry.npmjs.org/express/-/express-4.16.4.tgz", + "integrity": "sha512-j12Uuyb4FMrd/qQAm6uCHAkPtO8FDTRJZBDd5D2KOL2eLaz1yUNdUB/NOIyq0iU4q4cFarsUCrnFDPBcnksuOg==", + "dev": true, + "license": "MIT", + "dependencies": { + "accepts": "~1.3.5", + "array-flatten": "1.1.1", + "body-parser": "1.18.3", + "content-disposition": "0.5.2", + "content-type": "~1.0.4", + "cookie": "0.3.1", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "~1.1.2", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.1.1", + "fresh": "0.5.2", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "~2.3.0", + "parseurl": "~1.3.2", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.4", + "qs": "6.5.2", + "range-parser": "~1.2.0", + "safe-buffer": "5.1.2", + "send": "0.16.2", + "serve-static": "1.13.2", + "setprototypeof": "1.1.0", + "statuses": "~1.4.0", + "type-is": "~1.6.16", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/react-snap/node_modules/finalhandler": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.1.tgz", + "integrity": "sha512-Y1GUDo39ez4aHAw7MysnUD5JzYX+WaIj8I57kO3aEPT1fFRL4sr7mjei97FgnwhAyyzRYmQZaTHb2+9uZ1dPtg==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.2", + "statuses": "~1.4.0", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/react-snap/node_modules/http-errors": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", + "integrity": "sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==", + "dev": true, + "license": "MIT", + "dependencies": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.0", + "statuses": ">= 1.4.0 < 2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/react-snap/node_modules/iconv-lite": { + "version": "0.4.23", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.23.tgz", + "integrity": "sha512-neyTUVFtahjf0mB3dZT77u+8O0QB89jFdnBkd5P1JgYPbPaia3gXXOVL2fq8VyU2gMMD7SaN7QukTB/pmXYvDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-snap/node_modules/inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==", + "dev": true, + "license": "ISC" + }, + "node_modules/react-snap/node_modules/merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==", + "dev": true, + "license": "MIT" + }, + "node_modules/react-snap/node_modules/mime": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz", + "integrity": "sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ==", + "dev": true, + "license": "MIT", + "bin": { + "mime": "cli.js" + } + }, + "node_modules/react-snap/node_modules/minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha512-miQKw5Hv4NS1Psg2517mV4e4dYNaO3++hjAvLOAzKqZ61rH8NS1SK+vbfBWZ5PY/Me/bEWhUwqMghEW5Fb9T7Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/react-snap/node_modules/mkdirp": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha512-SknJC52obPfGQPnjIkXbmA6+5H15E+fR+E4iR2oQ3zzCLbd7/ONua69R/Gw7AgkTLsRG+r5fzksYwWe1AgTyWA==", + "deprecated": "Legacy versions of mkdirp are no longer supported. Please update to mkdirp 1.x. (Note that the API surface has changed to use Promises in 1.x.)", + "dev": true, + "license": "MIT", + "dependencies": { + "minimist": "0.0.8" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/react-snap/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true, + "license": "MIT" + }, + "node_modules/react-snap/node_modules/on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==", + "dev": true, + "license": "MIT", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/react-snap/node_modules/path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/react-snap/node_modules/qs": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", + "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/react-snap/node_modules/raw-body": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.3.3.tgz", + "integrity": "sha512-9esiElv1BrZoI3rCDuOuKCBRbuApGGaDPQfjSflGxdy4oyzqghxu6klEkkVIvBje+FF0BX9coEv8KqW6X/7njw==", + "dev": true, + "license": "MIT", + "dependencies": { + "bytes": "3.0.0", + "http-errors": "1.6.3", + "iconv-lite": "0.4.23", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/react-snap/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true, + "license": "MIT" + }, + "node_modules/react-snap/node_modules/send": { + "version": "0.16.2", + "resolved": "https://registry.npmjs.org/send/-/send-0.16.2.tgz", + "integrity": "sha512-E64YFPUssFHEFBvpbbjr44NCLtI1AohxQ8ZSiJjQLskAdKuriYEP6VyGEsRDH8ScozGpkaX1BGvhanqCwkcEZw==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "2.6.9", + "depd": "~1.1.2", + "destroy": "~1.0.4", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "~1.6.2", + "mime": "1.4.1", + "ms": "2.0.0", + "on-finished": "~2.3.0", + "range-parser": "~1.2.0", + "statuses": "~1.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/react-snap/node_modules/serve-static": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.13.2.tgz", + "integrity": "sha512-p/tdJrO4U387R9oMjb1oj7qSMaMfmOyd4j9hOFoxZe2baQszgHcSWjuya/CiT5kgZZKRudHNOA0pYXOl8rQ5nw==", + "dev": true, + "license": "MIT", + "dependencies": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.2", + "send": "0.16.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/react-snap/node_modules/setprototypeof": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", + "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/react-snap/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-snap/node_modules/statuses": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz", + "integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, "node_modules/react-spinners": { "version": "0.15.0", "resolved": "https://registry.npmjs.org/react-spinners/-/react-spinners-0.15.0.tgz", @@ -18991,6 +19955,31 @@ "deprecated": "Please use @jridgewell/sourcemap-codec instead", "license": "MIT" }, + "node_modules/sourcemapped-stacktrace-node": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/sourcemapped-stacktrace-node/-/sourcemapped-stacktrace-node-2.1.8.tgz", + "integrity": "sha512-xQOqfT5mquKLBp+H06WTeGYEQh7OF5wa44IPHbh+qNdTP15xSzxwISPml1xCweJ6DExDpDDxXe/P34wP+GdDrg==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "es6-promise": "^4.1.1", + "isomorphic-fetch": "^2.2.1", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">= 8.6.0" + } + }, + "node_modules/sourcemapped-stacktrace-node/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/spdy": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.2.tgz", @@ -20903,6 +21892,40 @@ "node": ">=10" } }, + "node_modules/uglify-js": { + "version": "3.4.10", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.4.10.tgz", + "integrity": "sha512-Y2VsbPVs0FIshJztycsO2SfPk7/KAF/T72qzv9u5EpQ4kB2hQoHlhNQTsNyy6ul7lQtqJN/AoWeS23OzEiEFxw==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "commander": "~2.19.0", + "source-map": "~0.6.1" + }, + "bin": { + "uglifyjs": "bin/uglifyjs" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/uglify-js/node_modules/commander": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.19.0.tgz", + "integrity": "sha512-6tvAOO+D6OENvRAh524Dh9jcfKTYDQAqvqezbCW82xj5X0pSrcpxtvRKHLG0yBY6SD7PSDrJaj+0AiOcKVd1Xg==", + "dev": true, + "license": "MIT" + }, + "node_modules/uglify-js/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/unbox-primitive": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.1.0.tgz", @@ -21069,6 +22092,13 @@ "browserslist": ">= 4.21.0" } }, + "node_modules/upper-case": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/upper-case/-/upper-case-1.1.3.tgz", + "integrity": "sha512-WRbjgmYzgXkCV7zNVpy5YgrHgbBv126rMALQQMrmzOVC4GM2waQ9x7xtm8VU+1yF2kWyPzI9zbZ48n4vSxwfSA==", + "dev": true, + "license": "MIT" + }, "node_modules/uri-js": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", @@ -22236,6 +23266,17 @@ "node": ">=10" } }, + "node_modules/yauzl": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", + "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer-crc32": "~0.2.3", + "fd-slicer": "~1.1.0" + } + }, "node_modules/yocto-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", diff --git a/package.json b/package.json index 2b15cf4..2ec4186 100644 --- a/package.json +++ b/package.json @@ -73,10 +73,29 @@ "lint": "eslint .", "lint:fix": "eslint . --fix", "start": "react-scripts start --host 0.0.0.0", - "build": "react-scripts build", + "build": "react-scripts build && react-snap", "test": "react-scripts test", "eject": "react-scripts eject" }, + "reactSnap": { + "include": [ + "/signin", + "/signup", + "/forgot-password", + "/privacy", + "/terms" + ], + "skipThirdPartyRequests": true, + "cacheAjaxRequests": false, + "puppeteerArgs": [ + "--no-sandbox", + "--disable-setuid-sandbox" + ], + "minifyHtml": { + "collapseWhitespace": true, + "removeComments": true + } + }, "eslintConfig": { "extends": [ "react-app", @@ -117,6 +136,7 @@ "glob": "^11.0.3", "globals": "^16.3.0", "postcss": "^8.5.3", + "react-snap": "^1.23.0", "tailwindcss": "^3.4.17", "typescript-eslint": "^8.38.0" } diff --git a/src/components/Paywall.js b/src/components/Paywall.js index 73de1f1..9b5c4a2 100644 --- a/src/components/Paywall.js +++ b/src/components/Paywall.js @@ -90,45 +90,69 @@ export default function Paywall() { // No active sub => pricing return ( -
-
-

Upgrade to AptivaAI

-

Choose the plan that fits your needs – cancel anytime.

+
+
+

Upgrade to Premium

+

Unlock AI-enhanced career planning and financial projections

- {/* Premium */} -
-

Premium

-
    -
  • Career milestone planning
  • -
  • Financial projections & benchmarks
  • -
  • 2 × resume optimizations / week
  • + {/* Single Premium Tier */} +
    +
    +

    AptivaAI Premium

    +

    Everything you need for career planning

    +
    + +
      +
    • + + AI Career Coach – Unlimited conversations with personalized guidance +
    • +
    • + + Career Roadmap – Milestone tracking with financial impact modeling +
    • +
    • + + 20-Year Financial Projections – Model multiple career scenarios +
    • +
    • + + Resume Optimizer – 3 AI-enhanced optimizations per week +
    • +
    • + + Retirement Planner – Beta access to retirement scenario modeling +
    -
    - - +
    + +
    + +

    Cancel anytime • No long-term commitment

    - {/* Pro */} -
    -

    Pro Premium

    -
      -
    • Everything in Premium
    • -
    • Priority GPT-4o usage & higher rate limits
    • -
    • 5 × resume optimizations / week
    • -
    - -
    - - -
    -
    - - +
    + +
); } diff --git a/src/components/RetirementPlanner.js b/src/components/RetirementPlanner.js index b66ffec..7124c83 100644 --- a/src/components/RetirementPlanner.js +++ b/src/components/RetirementPlanner.js @@ -6,6 +6,7 @@ import { Button } from './ui/button.js'; import RetirementChatBar from './RetirementChatBar.js'; import ScenarioDiffDrawer from './ScenarioDiffDrawer.js'; import ChatCtx from '../contexts/ChatCtx.js'; +import FinancialDisclaimer from './FinancialDisclaimer.js'; /* ------------------------------------------------------------------ * tiny class‑name helper @@ -133,9 +134,14 @@ export default function RetirementPlanner () { const baselineYears = simYearsMap[baselineId] ?? null; // renamed return ( -
- {/* ================= MAIN COLUMN =========================== */} -
+ +
+ {/* ================= MAIN COLUMN =========================== */} +
+ {/* Disclaimer spans above both columns */} +
+ +
{/* desktop add */} {!isMobile && (