diff --git a/AGENTS.md b/AGENTS.md index 463bbf6..7de0610 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -17,9 +17,9 @@ |-------|-----------|-------| | **Framework** | Next.js 16.1.1 (App Router) | Standalone output | | **Runtime** | Bun | Package management + scripts | -| **Database** | Prisma v6 + SQLite (dev) / PostgreSQL (prod) | Local dev uses SQLite | +| **Database** | Prisma v6 + PostgreSQL | PostgreSQL only (no SQLite) | | **Auth** | JWT (jose v6) + HttpOnly cookies + localStorage client cache | Custom | -| **UI** | Tailwind CSS v4 | Custom glass design system | +| **UI** | Tailwind CSS v4 | "Field Manual" light design system | | **Icons** | Phosphor Icons (light weight) | No thick-stroked icons | | **Animation** | Framer Motion v12 | Scroll reveals, stagger, hover physics | | **Fonts** | Space Grotesk (headings) + Plus Jakarta Sans (body) | No Inter/Roboto | @@ -27,15 +27,18 @@ | **Export** | docx, PDF (pdfkit), Excel (exceljs) | Resource downloads | | **Testing** | Vitest | unit + API + component tests | -## Design System — Ethereal Glass +## Design System — "Field Manual" (light theme) + +> NOTE: The "Ethereal Glass" dark design previously described here was reverted. The live app uses the light "Field Manual" system below. | Element | Spec | |---------|------| -| **Background** | OLED black (`#050505`) with radial gradient orbs | -| **Cards** | Glass-morphism with `backdrop-blur-xl` | -| **Accents** | Indigo/violet, emerald (success), amber (warning), rose (danger) | -| **Motion** | Custom cubic-bezier: `ease-premium`, `ease-spring`, `ease-out-heavy` | -| **Components** | Double-bezel glass cards, pill CTAs with trailing icon pattern | +| **Background** | Warm off-white (`#FAFAF7`) with subtle grain/border texture | +| **Cards** | `FieldCard` — solid surface, thin border, soft shadow, no glass blur | +| **Accents** | Primary orange (`#FF6B35`), ink scale for text, emerald (success), amber (warning), rose (danger) | +| **Motion** | Framer Motion scroll reveals, stagger, hover physics (no custom cubic-beziers) | +| **Components** | `FieldButton` (variants: default/outline/ghost), `FieldCard`, `FieldBadge`, `Alert` | +| **Tokens** | Defined in `globals.css` + Tailwind config (CSS variables, not arbitrary values) | ## Code Organization diff --git a/FIX-PLAN.md b/FIX-PLAN.md new file mode 100644 index 0000000..28f7c9c --- /dev/null +++ b/FIX-PLAN.md @@ -0,0 +1,133 @@ +# Interview Lab — Thorough Fix Plan + +> Audited 2026-07-19. A sequenced, merge-ready plan. Each phase: **goal → files → changes → verification**. +> Phases are independently shippable; **Phase 0 must land first**. + +--- + +## Phase 0 — Reconcile Reality & Delete Dead Code +*Why first: docs/architecture are wrong. Fix the map before the journey.* + +### 0.1 Documentation truth-up +**Files:** `AGENTS.md`, `README.md`, `REDESIGN-PLAN.md`, `REMEDIATION_PLAN.md`, `docs/architecture.md` +- Rewrite AGENTS.md "Design System" section: replace *"Ethereal Glass / OLED black / sky `#007EFF`"* with the live **"Field Manual" light theme** (`#FAFAF7` bg, `#FF6B35` accent, `FieldCard`/`FieldButton`). +- README Tech Stack: change `UI` row to "Tailwind v4 + Field Manual design system"; fix `Export` row ("pdfkit" → "pdfkit + manual PDF builder" or remove pdfkit after Phase 3). +- `REMEDIATION_PLAN.md`: delete false claim that `downloads/[id]/route.ts` is 879 lines (it's 53). +- Mark `REDESIGN-PLAN.md` as **superseded** (glass redesign was reverted) — or delete it. + +### 0.2 Delete dead code +| File | Reason | +|------|--------| +| `src/lib/browser-llm-integration.ts` (338 lines) | Not imported anywhere; fake rule-based AI | +| `src/components/interview-lab/UpgradeModal.tsx` | Stub, no-op | +| `src/components/interview-lab/SubscriptionBanner.tsx` | Stub, no-op | +| `src/lib/pricing.ts` (tier config) — *optional* | Only powers stubs; keep if PricingPage ever real | + +**Verify:** `grep -r "browser-llm-integration\|UpgradeModal\|SubscriptionBanner" src` → no results; `bun run build` passes. + +--- + +## Phase 1 — SOLID: AI Layer Refactor (SRP + OCP + DIP) +*Highest leverage: 4 routes share ~75-line duplicated JSON-extract loop, each calls the SDK directly.* + +### 1.1 `src/lib/ai/client.ts` — AIProvider abstraction (DIP) +```ts +export interface AIProvider { + complete(system: string, user: string, opts?: { schema?: ZodSchema; signal?: AbortSignal }): Promise; +} +export class ZAIProvider implements AIProvider { /* timeout 30s, abort, retry-once */ } +export const ai: AIProvider = new ZAIProvider(); +``` +- Add `AbortSignal.timeout(30000)` + `try/catch` around `ZAI.create().chat.completions.create`. + +### 1.2 `src/lib/ai/handlers.ts` — `createAIHandler` factory (OCP) +```ts +export function createAIHandler(buildPrompt, schema: ZodSchema) { + return async (req) => { /* auth → call ai.complete with schema → validate → return */ }; +} +``` +- Centralize `extractJsonArray`/`extractJsonObject` parsing into tested util `src/lib/ai/json.ts`. + +### 1.3 Split routes +- `src/lib/ai/coach.ts`, `resume.ts`, `cover-letter.ts`, `assessment.ts` — each exports `buildPrompt()` + a zod `schema`. +- Refactor `src/app/api/ai/{coach,resume-review,cover-letter,assessment-score}/route.ts` to ~15 lines each calling `createAIHandler`. + +### 1.4 Add zod schemas +- `src/lib/ai/schemas.ts`: `CoachFeedbackSchema`, `ResumeReviewSchema`, `CoverLetterSchema`, `AssessmentScoreSchema` (replaces runtime `as` casts). + +**Verify:** `__tests__/ai/client.test.ts` (mock `z-ai-web-dev-sdk`), `handlers.test.ts` (valid + malformed JSON → 500), `bun run test`. + +--- + +## Phase 2 — SOLID: Export Layer (SRP) +### 2.1 `src/lib/export/docx.ts` +- Move `generateDocx` out of `export/route.ts` into its own module. + +### 2.2 `src/lib/export/pdf.ts` — replace hand-rolled byte builder +- Use already-installed `pdfkit` (currently unused). Fixes **silent truncation** (`if (y < 50) break`) by paginating. +- Add `content` size guard (reject > 50k chars) to prevent abuse. + +### 2.3 `src/app/api/export/route.ts` +- Becomes ~12 lines: auth → dispatch to `docx.ts` / `pdf.ts`. + +**Verify:** `export.test.ts` generates real .docx/.pdf, asserts multi-page content isn't truncated. + +--- + +## Phase 3 — SOLID: Entitlement Honesty (LSP) +### 3.1 `src/lib/subscription/entitlement.ts` +```ts +export interface EntitlementService { canAccess(feature): boolean; tier: string; } +export class FreeEntitlement implements EntitlementService { canAccess() { return true; } } +``` +- `subscription-guard.ts` returns real interface; `use-subscription.ts` returns `FreeEntitlement` honestly (remove fake `-1`/no-op that *implies* gating). + +**Verify:** `subscription.test.ts`. + +--- + +## Phase 4 — Component Decomposition (SRP) +### 4.1 `MockInterview.tsx` (618 →) +`src/components/interview-lab/mock-interview/{Setup,ActiveSession,Complete,useInterview}.tsx` + +### 4.2 Standardize error/empty states +- `ResumeLab` raw red `
` → `Alert` component (already built in `ui/`). +- Add skeletons to `MockInterview`/`ResumeLab` to match `DashboardView`. + +### 4.3 A11y fix +- `QuestionBank`: remove nested interactive (inner "Practice" button inside `role="button"` div) → make card a real `
` with a separate button. + +**Verify:** `bun run lint`, component render tests. + +--- + +## Phase 5 — Infra & Correctness +### 5.1 Rate limiter (`middleware.ts`) +- Replace in-memory `Map` with **Upstash Redis** (`@upstash/ratelimit`) so it works across Vercel serverless. +- Trust `x-forwarded-for` only behind Vercel proxy; add `x-vercel-ip` fallback. + +### 5.2 Font drift (`globals.css`) +- `JetBrains Mono`/`Inter` declared but unused → align to Space Grotesk + Plus Jakarta Sans (per spec) or update spec. + +### 5.3 `db.ts` +- Gate `log: ['query']` behind explicit `LOG_QUERIES=1` env (confirm off in prod). + +--- + +## Effort & Sequencing + +| Phase | Work | Est. | Risk | +|-------|------|------|------| +| 0 | Doc truth-up + dead-code deletion | 1 day | 🟢 none | +| 1 | AI layer SOLID refactor + zod | 4 days | 🟡 medium (test coverage needed) | +| 2 | Export layer split + pdfkit | 1 day | 🟡 medium | +| 3 | Entitlement honesty | 1 day | 🟢 low | +| 4 | Component decomposition + UI polish | 4 days | 🟡 medium | +| 5 | Rate limiter + fonts + db | 2 days | 🟡 medium | + +**Total: ~13 dev-days.** Phases are independently shippable; Phase 0 must land first. + +--- + +## Suggested first PR +**"Phase 0: Reconcile docs & remove dead code"** — smallest diff, zero behavioral risk, unblocks everything. diff --git a/README.md b/README.md index aaa8fc2..0f40f1a 100644 --- a/README.md +++ b/README.md @@ -37,14 +37,14 @@ for aspiring Amazon Virtual Assistants. | Layer | Technology | |-------|-----------| | **Framework** | Next.js 16.1.1 (App Router, standalone) | -| **Runtime** | Bun | -| **Database** | Prisma v6 + SQLite (dev) / PostgreSQL (prod) | +| **Runtime** | Bun (CI uses npm) | +| **Database** | Prisma v6 + PostgreSQL (PostgreSQL only) | | **Auth** | Custom JWT sessions (jose) + HttpOnly cookies | -| **UI** | Tailwind CSS v4 + custom glass design system | +| **UI** | Tailwind CSS v4 + "Field Manual" light design system | | **Icons** | Phosphor Icons (light weight) | | **Fonts** | Space Grotesk (headings) + Plus Jakarta Sans (body) | | **AI** | Z AI Web Dev SDK for coaching, scoring, content generation | -| **Export** | docx, PDF (pdfkit), Excel (exceljs) | +| **Export** | docx, PDF (manual builder / pdfkit), Excel (exceljs) | ## 🚀 Getting Started @@ -90,7 +90,7 @@ src/ │ │ ├── assessments/ # Practice test assessments │ │ ├── profile/ # User profile (GET/PUT) │ │ ├── dashboard/ # Dashboard aggregation -│ │ ├── subscription/ # Checkout, status, usage, webhook +│ │ ├── subscription/ # Removed (product is free) │ │ ├── resume/ # Resume upload + AI review │ │ ├── cover-letter/ # Cover letter generation │ │ ├── ai/ # AI endpoints (coach, scoring, resume, cover) @@ -100,17 +100,17 @@ src/ │ │ └── export/ # DOCX/PDF/Excel export │ └── [pages]/ # Page routes ├── components/ -│ ├── interview-lab/ # Page components (glass design system) -│ └── ui/ # Shared primitives (glass-card, glass-button, etc.) +│ ├── interview-lab/ # Page components (Field Manual design system) +│ └── ui/ # Shared primitives (field-card, field-button, etc.) ├── lib/ │ ├── auth-helpers.ts # Server-side JWT + header auth -│ ├── pricing.ts # Tier configs (Free/Starter/Pro) and limits -│ ├── subscription-guard.ts # Feature access checks per tier +│ ├── pricing.ts # Tier configs (currently unused — product is free) +│ ├── subscription-guard.ts # Feature access checks (returns allowed: true) │ ├── types.ts # TypeScript interfaces │ └── utils.ts # cn() utility └── hooks/ # Custom React hooks -prisma/ # Prisma schema (SQLite/PostgreSQL) +prisma/ # Prisma schema (PostgreSQL) __tests__/ # Test suites ├── api/ # API route unit tests (218 tests) │ ├── interview-session.test.ts @@ -133,7 +133,7 @@ docs/ # PRD, architecture, feature specs bun test # Run specific test file -bun test __tests__/api/subscription.test.ts +bun test __tests__/api/resume-coverletter.test.ts # Run API tests only bun test __tests__/api/ @@ -149,9 +149,8 @@ bun test __tests__/api/ | `auth-login.test.ts` | 26 | Login flow, rate limiting, session, email sanitization | | `assessments.test.ts` | 20 | Assessment list/get/submit, answer key stripping | | `profile-dashboard.test.ts` | 23 | Profile whitelisting, sanitization, dashboard stats | -| `subscription.test.ts` | 31 | Pricing logic, checkout, tier validation, payments | | `resume-coverletter.test.ts` | 25 | Resume CRUD, cover-letter tones, truth flags | -| **Total** | **218** | **All API routes, all green** | +| **Total** | **187** | **All API routes, all green** | Tests use in-memory stubs — no database or server required. @@ -161,19 +160,19 @@ Tests use in-memory stubs — no database or server required. |---------|-------------| | `bun run dev` | Dev server with logging | | `bun run build` | Production build (standalone) | -| `bun run db:push` | Push Prisma schema to SQLite | +| `bun run db:push` | Push Prisma schema to PostgreSQL | | `bun run db:generate` | Generate Prisma client | | `bun run test` | Run test suite | | `bun run lint` | ESLint check | -## 🎨 Design System — Ethereal Glass +## 🎨 Design System — "Field Manual" (light theme) -The app uses a premium dark-mode glass aesthetic: +> The earlier "Ethereal Glass" dark design was reverted. The live app uses a clean light "Field Manual" system. -- **Palette:** OLED black (`#050505`) with radial gradient orbs, glass-morphism cards, `backdrop-blur-xl` -- **Colors:** Indigo/violet accents, emerald success, amber warnings, rose danger -- **Motion:** Custom cubic-bezier curves, Framer Motion scroll reveals, staggered animations -- **Components:** Double-bezel glass cards, pill CTAs, glass inputs/badges +- **Palette:** Warm off-white (`#FAFAF7`) with subtle grain/border texture, primary orange (`#FF6B35`) accents +- **Colors:** Ink scale for text, emerald success, amber warnings, rose danger +- **Motion:** Framer Motion scroll reveals, stagger, hover physics (no custom cubic-beziers) +- **Components:** `FieldCard` (solid surface, thin border, soft shadow), `FieldButton` (default/outline/ghost), `FieldBadge`, `Alert` - **Icons:** Phosphor Icons in `weight="light"` — no thick-stroked icons - **Typography:** Space Grotesk for headings, Plus Jakarta Sans for body @@ -181,7 +180,7 @@ The app uses a premium dark-mode glass aesthetic: | Variable | Description | |----------|-------------| -| `DATABASE_URL` | SQLite connection string (`file:./dev.db`) or PostgreSQL URL | +| `DATABASE_URL` | PostgreSQL connection URL | | `JWT_SECRET` | Secret for signing JWT session tokens | | `NEXT_PUBLIC_APP_URL` | App base URL | diff --git a/REDESIGN-PLAN.md b/REDESIGN-PLAN.md index 4cdf9a0..3cc78e8 100644 --- a/REDESIGN-PLAN.md +++ b/REDESIGN-PLAN.md @@ -1,6 +1,6 @@ # Redesign Plan — Interview Lab -> **Status:** All phases implemented. See git history for details. +> **Status:** SUPERSEDED. The "Ethereal Glass" dark design described here was reverted in favor of the live light "Field Manual" design system (see `AGENTS.md` Design System section). Kept for historical reference only. ## Design System — Ethereal Glass diff --git a/REMEDIATION_PLAN.md b/REMEDIATION_PLAN.md index e78da38..f9056bf 100644 --- a/REMEDIATION_PLAN.md +++ b/REMEDIATION_PLAN.md @@ -87,8 +87,8 @@ Interview Lab is a **free companion** to [Project Amazon PH Academy](https://pro - Model assessment attempts properly (user, timestamps, answers, score, rubrics, status, AI version) ### P2.3 — Download route decomposition -**Files:** `src/app/api/downloads/[id]/route.ts` (879 lines) -**Problem:** Monolithic route handles auth, tier checks, 4 document formats, database access, and analytics. +**Files:** `src/app/api/downloads/[id]/route.ts` (53 lines — earlier "879-line" estimate was inaccurate) +**Problem:** Route handles auth, tier checks, multiple document formats, database access, and analytics. **Fix:** - Extract document builders: `src/lib/documents/pdf.ts`, `docx.ts`, `xlsx.ts`, `text.ts` - Extract template renderers: `src/lib/templates/amazon-training.ts` @@ -112,7 +112,7 @@ Interview Lab is a **free companion** to [Project Amazon PH Academy](https://pro - Add browser tests for critical user journeys ### P2.6 — Operational documentation -**Problem:** README documents Bun runtime but CI uses npm; describes SQLite but schema is PostgreSQL; no standalone output config. +**Problem:** README previously documented Bun runtime but CI uses npm; described SQLite but schema is PostgreSQL. (README corrected 2026-07-19; standalone output already in `next.config.ts`.) **Fix:** - Standardize on one package manager (npm, given CI/Vercel use it) - Update README to reflect PostgreSQL-only schema diff --git a/src/lib/browser-llm-integration.ts b/src/lib/browser-llm-integration.ts deleted file mode 100644 index 019863a..0000000 --- a/src/lib/browser-llm-integration.ts +++ /dev/null @@ -1,338 +0,0 @@ -"use client"; - -import { toast } from '@/hooks/use-toast'; - -// Browser-based LLM integration that works without API keys -// Uses local LLM fallback and rule-based system for Amazon VA career guidance - -// Extend Window type to support the experimental window.ai API -declare global { - interface Window { - ai?: { - models?: { - available(): Promise<{ name: string }[]>; - }; - generateText?(model: { name: string }, options: { prompt: string; max_tokens?: number; temperature?: number }): Promise<{ text: string }>; - }; - } -} - -interface LLMResponse { - score?: number; - missingKeywords?: string[]; - weakSections?: string[]; - improvedSummary?: string; - improvedBullets?: string[]; - skillsRecommendations?: string[]; - truthWarnings?: string[]; - improvedVersion?: string; - draftLetter?: string; - shorterVersion?: string; - subjectLine?: string; - customizationTips?: string[]; - claimsToVerify?: string[]; - correctDecisions?: string[]; - incorrectDecisions?: string[]; - missedOpportunities?: string[]; - recommendedNextStep?: string; - modelAnswer?: string; -} - -class BrowserLLMIntegration { - private static instance: BrowserLLMIntegration; - private conversationHistory: { role: 'system' | 'user' | 'assistant'; content: string }[] = []; - - private constructor() { - this.initializeSystemPrompt(); - } - - public static getInstance(): BrowserLLMIntegration { - if (!BrowserLLMIntegration.instance) { - BrowserLLMIntegration.instance = new BrowserLLMIntegration(); - } - return BrowserLLMIntegration.instance; - } - - private initializeSystemPrompt() { - this.conversationHistory = [ - { - role: 'system', - content: `You are an Amazon VA career preparation assistant. Your job is to help users prepare for Amazon marketplace virtual assistant roles, especially Amazon PPC, Seller Central support, listing support, reporting, and agency operations roles. You must be practical, honest, and role-specific. Help users explain their real skills clearly without exaggerating or fabricating experience. Never guarantee job placement, interview success, ranking results, ACoS improvement, or Amazon account outcomes.` - } - ]; - } - - private isLocalAvailable(): boolean { - // Check if we're in a browser environment - return typeof window !== 'undefined' && typeof window.ai !== 'undefined'; - } - - public async generateResponse( - prompt: string, - responseType: 'resume' | 'assessment' | 'cover-letter' - ): Promise { - try { - // First try local browser AI if available - if (this.isLocalAvailable()) { - try { - const response = await this.callLocalAI(prompt); - if (response) { - return this.parseResponse(response, responseType); - } - } catch (error) { - console.warn('Local AI not available, falling back to rule-based system:', error); - } - } - - // Fall back to rule-based system - return this.ruleBasedResponse(prompt, responseType); - - } catch (error) { - console.error('LLM integration error:', error); - toast({ - title: "AI Service Temporarily Unavailable", - description: "Using enhanced rule-based system for your request.", - variant: "default", - }); - return this.ruleBasedResponse(prompt, responseType); - } - } - - private async callLocalAI(prompt: string): Promise { - // Try to use browser AI API if available - if (typeof window !== 'undefined' && window.ai?.models?.available()) { - const availableModels = await window.ai.models.available(); - if (availableModels.length > 0) { - const model = availableModels[0]; - const generateText = window.ai!.generateText; - if (!generateText) return null; - const response = await generateText(model, { - prompt: `${this.getConversationContext()}\n\nUser Request: ${prompt}`, - max_tokens: 1000, - temperature: 0.3, - }); - return response.text; - } - } - return null; - } - - private getConversationContext(): string { - return this.conversationHistory - .slice(1) // Exclude system prompt - .map(msg => `${msg.role === 'user' ? 'User' : 'Assistant'}: ${msg.content}`) - .join('\n\n'); - } - - private parseResponse(response: string, responseType: string): LLMResponse { - try { - // Try to parse JSON response - const jsonMatch = response.match(/\{[\s\S]*\}/); - if (jsonMatch) { - const parsed = JSON.parse(jsonMatch[0]); - return parsed; - } - - // If no valid JSON, create structured response based on responseType - return this.fallbackResponse(response, responseType); - - } catch (error) { - return this.fallbackResponse(response, responseType); - } - } - - private ruleBasedResponse(prompt: string, responseType: string): LLMResponse { - const lowerPrompt = prompt.toLowerCase(); - - switch (responseType) { - case 'resume': - return this.generateResumeResponse(lowerPrompt); - case 'assessment': - return this.generateAssessmentResponse(lowerPrompt); - case 'cover-letter': - return this.generateCoverLetterResponse(lowerPrompt); - default: - return this.generateGenericResponse(lowerPrompt); - } - } - - private generateResumeResponse(prompt: string): LLMResponse { - const score = this.calculateResumeScore(prompt); - const missingKeywords = this.extractMissingKeywords(prompt); - const weakSections = this.extractWeakSections(prompt); - - return { - score, - missingKeywords, - weakSections, - improvedSummary: this.generateImprovedSummary(prompt), - improvedBullets: this.generateImprovedBullets(prompt), - skillsRecommendations: this.generateSkillsRecommendations(prompt), - truthWarnings: this.generateTruthWarnings(prompt), - improvedVersion: this.generateImprovedVersion(prompt), - }; - } - - private generateAssessmentResponse(prompt: string): LLMResponse { - const score = this.calculateAssessmentScore(prompt); - const correctDecisions = this.extractCorrectDecisions(prompt); - const incorrectDecisions = this.extractIncorrectDecisions(prompt); - - return { - score, - correctDecisions, - incorrectDecisions, - missedOpportunities: this.generateMissedOpportunities(prompt), - recommendedNextStep: this.generateRecommendedNextStep(prompt), - modelAnswer: this.generateModelAnswer(prompt), - }; - } - - private generateCoverLetterResponse(prompt: string): LLMResponse { - return { - draftLetter: this.generateCoverLetterDraft(prompt), - shorterVersion: this.generateShorterVersion(prompt), - subjectLine: this.generateSubjectLine(prompt), - customizationTips: this.generateCustomizationTips(prompt), - claimsToVerify: this.generateClaimsToVerify(prompt), - }; - } - - private calculateResumeScore(prompt: string): number { - if (prompt.includes('amazon') && prompt.includes('ppc') && prompt.includes('seller')) { - return 85; - } else if (prompt.includes('amazon') && prompt.includes('experience')) { - return 70; - } - return 40; - } - - private extractMissingKeywords(prompt: string): string[] { - const keywords = ['Seller Central', 'PPC reporting', 'ACoS', 'ROAS', 'search term reports']; - const foundKeywords = keywords.filter(keyword => - prompt.includes(keyword.toLowerCase()) - ); - return keywords.filter(keyword => !foundKeywords.includes(keyword)); - } - - private extractWeakSections(prompt: string): string[] { - const sections: string[] = []; - if (!prompt.includes('metrics') && !prompt.includes('results')) sections.push('Metrics and outcomes'); - if (!prompt.includes('ammazon') && !prompt.includes('va')) sections.push('Professional Summary'); - if (!prompt.includes('campaigns') && !prompt.includes('structure')) sections.push('Campaign Structure'); - return sections.slice(0, 2); - } - - // Helper methods for generating responses - private generateImprovedSummary(prompt: string): string { - return 'Detail-oriented Virtual Assistant with training in Amazon Seller Central support, PPC reporting, keyword research workflows, and client communication. Familiar with Amazon PPC metrics including ACoS, ROAS, CTR, CPC, and CVR.'; - } - - private generateImprovedBullets(prompt: string): string[] { - return [ - 'Reviewed Amazon PPC search term reports and flagged high-click, zero-sale terms for negative keyword review', - 'Prepared weekly PPC performance summaries using spend, sales, ACoS, ROAS, and conversion data' - ]; - } - - private generateSkillsRecommendations(prompt: string): string[] { - return ['Amazon Seller Central', 'Amazon Ads Console', 'PPC Reporting', 'Keyword Research', 'Search Term Report Analysis']; - } - - private generateTruthWarnings(prompt: string): string[] { - return []; - } - - private generateImprovedVersion(prompt: string): string { - return prompt; - } - - private calculateAssessmentScore(prompt: string): number { - if (prompt.includes('metrics') && prompt.includes('action') && prompt.includes('data')) { - return 85; - } else if (prompt.includes('data') && prompt.includes('risk')) { - return 70; - } - return 50; - } - - private extractCorrectDecisions(prompt: string): string[] { - return ['You attempted the exercise']; - } - - private extractIncorrectDecisions(prompt: string): string[] { - return []; - } - - private generateMissedOpportunities(prompt: string): string[] { - return ['Try to include more specific metrics and reasoning']; - } - - private generateRecommendedNextStep(prompt: string): string { - return 'Review the relevant guide and try again'; - } - - private generateModelAnswer(prompt: string): string { - return 'Please review the assessment data and provide detailed analysis with specific metrics and action recommendations.'; - } - - private generateCoverLetterDraft(prompt: string): string { - const roleMatch = prompt.match(/role:\s*(.*?)(?:\n|$)/i); - const targetRole = roleMatch ? roleMatch[1] : 'Amazon VA'; - - return `Dear Hiring Manager, - -I am applying for the ${targetRole} role. I have a strong interest in Amazon marketplace operations and have been training in PPC workflows, search term report review, campaign organization, keyword research, and performance reporting. - -I understand the importance of tracking key metrics such as spend, sales, ACoS, ROAS, CTR, CPC, orders, and conversion rate. I can support a team by preparing reports, reviewing search terms, flagging high-click zero-sale keywords, documenting optimization actions, and following campaign naming and QA checklists carefully. - -I am comfortable working with SOPs, Google Sheets, ClickUp, and Amazon-related tools. I value accuracy, clear communication, and consistent documentation. - -Thank you for considering my application. - -Sincerely, -[Your Name]`; - } - - private generateShorterVersion(prompt: string): string { - const roleMatch = prompt.match(/role:\s*(.*?)(?:\n|$)/i); - const targetRole = roleMatch ? roleMatch[1] : 'Amazon VA'; - - return `Hi, I am applying for the ${targetRole} role. I have trained in Amazon PPC workflows, search term reports, and client communication. I can support your team with organized reporting, keyword analysis, and SOP-driven task execution.`; - } - - private generateSubjectLine(prompt: string): string { - const roleMatch = prompt.match(/role:\s*(.*?)(?:\n|$)/i); - const targetRole = roleMatch ? roleMatch[1] : 'Amazon VA'; - - return `Application for ${targetRole} Position`; - } - - private generateCustomizationTips(prompt: string): string[] { - return ['Add specific tool experience if you have it', 'Mention any relevant training or certifications']; - } - - private generateClaimsToVerify(prompt: string): string[] { - return ['Verify any tool familiarity mentioned']; - } - - private generateGenericResponse(prompt: string): LLMResponse { - return { - score: 50, - missingKeywords: ['Amazon', 'PPC', 'Seller Central'], - weakSections: ['Professional Summary'], - improvedSummary: 'Amazon-focused Virtual Assistant with training in PPC workflows, reporting, and client communication.', - improvedBullets: [], - skillsRecommendations: ['Amazon Seller Central', 'PPC Reporting'], - truthWarnings: [], - improvedVersion: prompt, - }; - } - - private fallbackResponse(text: string, responseType: string): LLMResponse { - console.log('Using fallback response for:', responseType); - return this.ruleBasedResponse(text, responseType); - } -} - -export { BrowserLLMIntegration }; \ No newline at end of file