feat: initial docs repo with project inventory and all documentation

- Added REPO_INVENTORY.md with all repos, branches, remotes, and staging info
- Added .gitignore
- Synced all existing docs from local workspace
- Centralized documentation hub for GrowQR team
This commit is contained in:
-Puter
2026-06-22 15:04:27 +05:30
commit e6685203fe
71 changed files with 35044 additions and 0 deletions

6
.gitignore vendored Normal file
View File

@@ -0,0 +1,6 @@
.DS_Store
*.tmp
*.log
node_modules/
.env
.env.local

View File

@@ -0,0 +1,223 @@
# Codex Master Parallel Agent Prompt
Paste this into a fresh Codex app session.
```text
You are the lead implementation orchestrator for the GrowQR repo at /Users/puter/Workspace/growqr.
Your job is to complete all four new services in parallel using background/sub-agents and keep them running in an implementation-review loop until the work is done. Do not stop after one slice. Do not pause to ask whether you should continue unless there is a true blocker that makes continued implementation unsafe.
## Primary Objective
Fully implement these four services in this repo, using the existing Python FastAPI template and existing repo patterns:
1. /Users/puter/Workspace/growqr/pathways-service
2. /Users/puter/Workspace/growqr/matchmaking-service
3. /Users/puter/Workspace/growqr/marketplace-service
4. /Users/puter/Workspace/growqr/social-branding-service
Each service already has:
- docs/PRD.md
- docs/plan.md
There is also a master orchestration plan here:
- /Users/puter/Workspace/growqr/docs/Four_Service_Overnight_Execution_Plan.md
You must read those docs first and use them as the source of truth for implementation order, scope, dependencies, and review gates.
## Mandatory Working Style
You must behave as a persistent engineering manager plus implementer, not as a one-shot code assistant.
You must:
- spawn background/sub-agents for parallel work
- keep working until all four services reach a genuinely usable implementation state
- use a develop -> test -> review -> fix loop continuously
- update plan checklists inside each service as phases complete
- avoid stopping after partial progress
- make reasonable assumptions and continue
- only ask the user a question if there is a real product contradiction or destructive architecture risk
You must not:
- stop after a single phase and ask “should I continue?”
- stop just because an external API is unavailable
- stop because OAuth, scraping, payments, or third-party integrations are incomplete
- over-focus on one service while ignoring the others
- silently drift outside the plans without documenting the reason
## Completion Standard
Keep going until each service:
- boots locally
- has real models and APIs
- has tests for core flows
- has seed/demo data or fixtures
- has Docker/Compose compatibility
- has README and plan docs updated
- has major PRD features implemented where feasible
- has deferred items explicitly documented only where they are truly blocked by external systems, legal constraints, or unresolved business decisions
“Done” does not mean “I built a scaffold.” It means the service is materially implemented end to end.
## Repository Context To Read First
Read these before implementation:
- /Users/puter/Workspace/growqr/docs/Four_Service_Overnight_Execution_Plan.md
- /Users/puter/Workspace/growqr/docs/Meeting_Notes_3_Week_Delivery_Plan.md
- /Users/puter/Workspace/growqr/docs/PRD_Portfolio_Summary.md
- /Users/puter/Workspace/growqr/pathways-service/docs/PRD.md
- /Users/puter/Workspace/growqr/pathways-service/docs/plan.md
- /Users/puter/Workspace/growqr/matchmaking-service/docs/PRD.md
- /Users/puter/Workspace/growqr/matchmaking-service/docs/plan.md
- /Users/puter/Workspace/growqr/marketplace-service/docs/PRD.md
- /Users/puter/Workspace/growqr/marketplace-service/docs/plan.md
- /Users/puter/Workspace/growqr/social-branding-service/docs/PRD.md
- /Users/puter/Workspace/growqr/social-branding-service/docs/plan.md
- /Users/puter/Workspace/growqr/fastapi-service-template/README.md
- /Users/puter/Workspace/growqr/upskilling_services/services/interview-service/README.md
- /Users/puter/Workspace/growqr/qscore_service/README.md
Inspect the code of existing services before making assumptions.
## Parallelization Plan
Create a top-level execution plan, then spawn:
- one background builder agent for Pathways
- one background builder agent for Matchmaking
- one background builder agent for Marketplace
- one background builder agent for Social Branding
- one background reviewer agent that repeatedly reviews all changed code for bugs, regressions, missing tests, broken assumptions, and plan drift
The reviewer agents job is not to implement large features first. Its job is to find defects and missing coverage continuously while the builders are working.
You should continue coordinating these agents until the full program is implemented as far as possible in this session.
## Dependency Order
Respect this order:
1. Pathways must stabilize shared user context, recommendation context, and pathway state contracts first.
2. Matchmaking and Marketplace can build in parallel once Pathways contracts are clear enough.
3. Social Branding should align to Pathways persona/goal/archetype contracts, but should continue independently using placeholders if needed.
Do not block all work waiting for Pathways to be perfect. Use provisional contracts, then reconcile.
## Scope And Delivery Rules
You must attempt to implement the PRDs broadly, but be intelligent about execution order.
When a feature can be implemented with an internal adapter, mock, stub, manual workflow, or admin-assisted fallback, do that now instead of stopping.
Examples:
- scraping unavailable -> create ingestion/import/admin pipeline and scraper adapter interface
- OAuth unavailable -> create manual import adapter and provider interface
- payment gateway unavailable -> create internal transaction state machine and fake payment confirmation flow
- analytics unavailable -> persist locally computed metrics and expose APIs
- external posting unavailable -> build draft generation, approval, and publish confirmation flow
Do not throw away the full PRD vision. Preserve it in:
- models
- adapters
- events
- configuration
- deferred docs
But implement the highest-value runnable version first.
## Service-Specific Expectations
### Pathways
- implement Option A fully first
- build questionnaire, profile ingest, generation, activation, weekly plans, report data, recommendation context
- preserve extension points for Option B, Q-scores, adaptive regeneration, and wider orchestration
### Matchmaking
- implement seeker feed, manual/admin ingestion, ranking, thresholds, feedback loop, action tracking
- preserve extension points for scrapers, enrichment, employer-side flows, and advanced weighting
### Marketplace
- implement provider application, approval, listings, browse/search/filter, recommendations, booking state machine
- fully implement live 1:1, async review, done-for-you first
- preserve extension points for payments, retainer, group sessions, guarantees, demand aggregation, and pre-booking
### Social Branding
- implement LinkedIn-first individual flow
- build import/audit, Brand Score, persona strategy, content calendar, draft generation, approval queue, publish confirmation, dashboard
- preserve extension points for OAuth, multi-platform support, enterprise workflows, and auto-posting
## Review Loop Requirements
After each meaningful implementation chunk:
- run relevant tests
- add tests if missing
- review changed code against PRD and plan
- update checkboxes in docs/plan.md
- continue immediately to the next phase
If a builder agent finishes its assigned phases early, reassign it to help:
- fix reviewer findings
- add tests
- harden Docker/Compose
- improve docs
- complete deferred-but-feasible items
## Stop Conditions
Do not stop unless one of these is true:
- there is a direct contradiction between required documents that materially changes implementation
- continuing would require a destructive schema decision that could break all four services
- a missing secret, API, or external integration cannot be bypassed with a fallback and blocks a critical required path
If you hit a stop condition:
- document the blocker clearly
- propose the exact smallest decision needed
- continue all unaffected work in parallel
## Deliverables Before You Finally Stop
Before ending the session, make sure there is:
- implemented code in all four service folders
- updated docs/plan.md checklists
- updated READMEs where needed
- tests passing where feasible
- clear notes on any real blockers or remaining external integration work
Start now by:
1. reading the master plan and all four service plans
2. building a concise orchestration plan
3. spawning the sub-agents
4. beginning implementation immediately
5. continuing until the whole program is substantially complete
```
## Shorter Version
Use this if you want a tighter prompt:
```text
Act as the lead orchestrator for /Users/puter/Workspace/growqr and complete these four services in parallel using background/sub-agents:
- /Users/puter/Workspace/growqr/pathways-service
- /Users/puter/Workspace/growqr/matchmaking-service
- /Users/puter/Workspace/growqr/marketplace-service
- /Users/puter/Workspace/growqr/social-branding-service
Read first:
- /Users/puter/Workspace/growqr/docs/Four_Service_Overnight_Execution_Plan.md
- /Users/puter/Workspace/growqr/docs/Meeting_Notes_3_Week_Delivery_Plan.md
- /Users/puter/Workspace/growqr/docs/PRD_Portfolio_Summary.md
- each services docs/PRD.md
- each services docs/plan.md
Spawn 4 builder agents + 1 reviewer agent. Keep them running in a develop -> test -> review -> fix loop until all four services are materially implemented end to end. Do not stop after a slice and do not ask whether to continue unless there is a true blocker.
Use fallbacks instead of stopping:
- admin/manual ingestion instead of scrapers
- internal/fake transaction flow instead of real payments
- manual import instead of blocked OAuth
- adapter interfaces for future integrations
Pathways first for shared contracts, then Matchmaking and Marketplace in parallel, then Social Branding aligned to Pathways context. Update each docs/plan.md checklist as phases complete. Before stopping, ensure each service has real models, APIs, tests, Docker compatibility, and explicit documentation of any truly blocked remainder.
```

View File

@@ -0,0 +1,215 @@
# Four-Service Overnight Execution Plan
## Goal
By tomorrow, the target is not full PRD completion. The target is four end-to-end MVP services that are coherent, testable, Docker-runnable, and handoff-ready enough for the next team or overnight agents to keep iterating without inventing architecture.
The only realistic way to do that is:
1. lock a narrow MVP cut for each service now
2. freeze shared contracts now
3. let agents implement against those frozen cuts
4. force a develop -> test -> review loop on every phase
If the agents try to implement PRD breadth, they will fail by morning.
## Hard Decisions Locked Now
These decisions are made now and should not be reopened overnight.
### Shared product decisions
- Treat all four services as MVP delivery, not PRD-complete delivery.
- Prefer manual/admin-assisted workflows over automation where automation depends on unstable third-party APIs.
- Deliver backend-first. Demo or admin pages are optional. Full polished frontend is not part of the overnight target.
- Keep auth simple for now: internal/demo-safe access pattern or stubbed auth dependency, not production auth hardening.
- Every service must support seeded demo data so flows can be verified without external integrations.
### Shared technical decisions
- Stack: Python, FastAPI, `uv`, async SQLAlchemy, Docker, Docker Compose, optional Postgres and Redis.
- Follow the service template already created in this repo.
- Use Postgres as the main persisted state in Docker mode.
- Use Redis only for async jobs, recomputation triggers, or event fan-out. If Redis blocks progress, keep a DB-backed fallback.
- Use adapters for all unstable integrations: LinkedIn, social platform posting, scraping, payments, analytics sync.
- Use deterministic logic for first-pass ranking/generation whenever possible. LLM use should enhance copy or explanation, not block core flow correctness.
### Shared scope decisions
- Pathways: implement Option A only. Option B exists as future extension points and data model placeholders.
- Matchmaking: seeker-side opportunity feed only. Admin/manual opportunity ingestion only.
- Marketplace: implement core onboarding + browse + booking around 3 formats only: live 1:1, async review, done-for-you.
- Social Branding: individual only, LinkedIn-first, manual/import-based data sync fallback, approval-first workflow.
## Explicitly Deferred Across The Board
These are not overnight goals:
- production-grade scraping pipelines
- multi-provider OAuth completion across all external platforms
- employer portal
- enterprise social branding
- real payment gateway, payouts, escrow, commission settlement
- wallet integration beyond stubs
- all 11 Pathways services at production orchestration depth
- polished mobile/web UI beyond minimal demo/admin support
- perfect analytics, alerting, and operational tooling
If an overnight agent starts building one of these, it is off-plan.
## Shared Contracts To Freeze Before Coding
All four services should align on these shared payload shapes.
### `profile_snapshot`
```json
{
"org_id": "growqr",
"user_id": "user-123",
"region": "india",
"current_role": "Product Analyst",
"years_experience": 3,
"industries": ["saas", "edtech"],
"skills": ["sql", "analytics", "stakeholder management"],
"goals": ["move into product management"],
"preferred_roles": ["product manager"],
"preferred_locations": ["remote", "bengaluru"],
"salary_range": {"min": 1200000, "max": 1800000, "currency": "INR"},
"pathway_archetype": null,
"q_scores": {},
"brand_score": null
}
```
### `service_recommendation`
```json
{
"user_id": "user-123",
"service": "matchmaking",
"reason_codes": ["skill_gap", "job_search_phase"],
"priority": "high",
"metadata": {}
}
```
### Core events
- `pathway.generated`
- `pathway.activated`
- `pathway.updated`
- `matchmaking.feed_generated`
- `matchmaking.action_recorded`
- `marketplace.booking_created`
- `marketplace.booking_completed`
- `social_branding.brand_score_updated`
- `social_branding.content_approved`
If a service cannot emit through Redis yet, it should still persist an event record and expose an internal retrieval endpoint.
## Service Order
### Recommended overnight order
1. Pathways
2. Matchmaking and Marketplace in parallel
3. Social Branding after Pathways persona/profile contract is stable
4. Final review pass across all four
### Why this order
- Pathways defines the shared user context, goals, pathway phase, and recommendation triggers.
- Matchmaking and Marketplace both depend on those user signals.
- Social Branding depends on persona/archetype and pathway milestones, so it should not invent those independently.
## Optimal Agent Topology
### Best case: 5 loops
- Builder 1: Pathways
- Builder 2: Matchmaking
- Builder 3: Marketplace
- Builder 4: Social Branding
- Reviewer loop: reads changed code/doc/tests and only reports defects, gaps, regressions, and missing tests
### If only 2 strong overnight loops are practical
Run in two waves:
1. Pathways + Marketplace
2. Matchmaking + Social Branding
Pathways must go first either way.
## Mandatory Agent Loop
Every overnight agent must follow this exact loop:
1. Read:
- this master plan
- the service `docs/PRD.md`
- the service `docs/plan.md`
- [docs/Meeting_Notes_3_Week_Delivery_Plan.md](./Meeting_Notes_3_Week_Delivery_Plan.md)
- [docs/PRD_Portfolio_Summary.md](./PRD_Portfolio_Summary.md)
- the service template and at least one implemented service in this repo
2. Implement only the current phase.
3. Run tests for that phase.
4. Review the result against the service acceptance checklist.
5. Update the checklist in `docs/plan.md`.
6. Move to the next phase only if the current phase is green.
## Stop Rules
An agent must not stop for these reasons:
- external API unavailable
- payment provider unavailable
- OAuth not configured
- scraping legality/rate-limit uncertainty
Instead it must:
- create an adapter interface
- implement a stub/manual fallback
- mark the real integration as deferred
- continue delivering the internal flow
An agent should stop only for:
- destructive schema uncertainty across services
- direct contradiction between this plan and the PRD
- a missing dependency that makes the service impossible to boot locally
## Suggested Skills And Context
If the agent environment supports local skills, the most relevant ones are:
- `brainstorming`
- `avoid-feature-creep`
- `doc-coauthoring`
- `native-data-fetching`
Local context files to load first:
- [docs/Meeting_Notes_3_Week_Delivery_Plan.md](./Meeting_Notes_3_Week_Delivery_Plan.md)
- [docs/PRD_Portfolio_Summary.md](./PRD_Portfolio_Summary.md)
- [fastapi-service-template/README.md](../fastapi-service-template/README.md)
- [upskilling_services/services/interview-service/README.md](../upskilling_services/services/interview-service/README.md)
- [qscore_service/README.md](../qscore_service/README.md)
## Shared Done Definition
By morning, each service should meet this minimum bar:
- boots locally with `uv run`
- boots in Docker Compose
- has a real domain model, not placeholders only
- has core API routes for the MVP journey
- has at least one worker/background flow if needed
- has tests for core happy paths
- has seed/demo data or fixture setup
- has a clear `docs/plan.md` with checkboxes updated
- has an explicit deferred list
Anything below that is still planning, not delivery.

View File

@@ -0,0 +1,117 @@
1. Interview-to-Offer Accelerator
Promise
“Prepare me for this specific interview and help me convert it into an offer.”
Uses
Interview service
Roleplay service
Resume service
Q Score
Grow Agent
Why it sells
People pay when an interview is already scheduled. The urgency is real.
Output
Interview prep plan
Likely questions
Mock interview sessions
Behavioral/story bank
Resume-based talking points
Weakness diagnosis
Final readiness score
2. Career Transition Accelerator
Promise
“Help me reposition from my current career into a better-fit role.”
Uses
Resume service
Social branding
Matchmaking
Q Score
Interview
Roleplay
Grow Agent
Why it sells
Career switching is confusing and emotionally expensive. People need a system, not just a resume.
Output
Target role recommendation
Transferable skills map
Repositioned resume
LinkedIn/profile rewrite
Interview narrative: “why Im switching”
Practice conversations
30/60/90 transition plan
3. Salary / Offer Negotiation War Room
Promise
“Help me negotiate my offer, raise, or promotion conversation.”
Uses
Roleplay service
Matchmaking
Q Score
Resume service
Social branding
Grow Agent
Why it sells
Direct financial ROI. If the user gets even $5k more, the product paid for itself.
Output
Offer analysis
Market positioning
Leverage map
Counteroffer script
Email drafts
Live-call practice
Objection handling
Confidence score
4. Promotion & Leadership Readiness System
Promise
“Help me become promotion-ready and make a strong case for my next level.”
Uses
Q Score
Roleplay service
Resume service
Social branding
Matchmaking
Grow Agent
Why it sells
This expands GrowQR beyond job seekers. Employed professionals have money and a clear career incentive.
Output
Promotion readiness score
Achievement narrative
Evidence packet
Manager conversation script
Leadership gap map
Internal brand plan
60/90-day promotion plan
5. Personal Brand & Opportunity Engine
Promise
“Make me visible and credible so better opportunities come to me.”
Uses
Social branding
Resume service
Matchmaking
Q Score
Roleplay service
Grow Agent
Why it sells
This is less urgent than interview/negotiation, but better for recurring revenue.
Output
LinkedIn/profile rewrite
Positioning statement
Content pillars
Weekly post drafts
Target audience map
Networking scripts
Brand growth score
My recommended premium lineup
If I had to pick only the strongest 4:
Interview-to-Offer Accelerator
Career Transition Accelerator
Salary / Offer Negotiation War Room
Promotion & Leadership Readiness System
Then use:
Job Search Lite as free acquisition
Personal Brand Engine as subscription/add-on
That positioning is much stronger than competing with job boards or auto-apply tools.

Binary file not shown.

View File

@@ -0,0 +1,195 @@
# Meeting Notes: 3-Week Delivery Plan
## Goal of This Discussion
Align on what we can realistically deliver from our side in **2 to 3 weeks max**, including:
- build scope
- integration points
- testing
- handoff to the next team
This note covers only the four in-scope PRDs:
- Pathways
- Matchmaking
- Marketplace
- Social Branding
Upskilling is already complete and excluded from this plan.
## Recommended Position in the Meeting
We should position this as a **focused MVP delivery**, not a full PRD-complete release.
If we try to implement all four PRDs at full depth in 3 weeks, quality will drop and handoff risk will increase. The right plan is:
- ship the **core user journeys**
- keep advanced automation and edge-case workflows out of v1
- finish with a stable integration and handoff package
**Bottom line:** a strong **3-week MVP** is realistic. A **2-week version** is possible only if we cut harder and treat it as an internal alpha.
## What We Can Realistically Deliver in 3 Weeks
### 1. Pathways
We can deliver:
- questionnaire flow
- LinkedIn/resume-based input only
- career option generation
- visual career web or list/card equivalent if web is too heavy for v1
- basic skill-gap and recommendation output
- pathway activation flow
- simple weekly journey structure
- report v1 or exportable summary
We should not commit now to:
- full premium psychometric pathway logic
- all 25 Q-Score dependent adaptive behaviors
- fully dynamic report regeneration
- deep 11-service orchestration logic at production depth
### 2. Matchmaking
We can deliver:
- seeker-side opportunity feed
- core matching logic using available profile/Q-Score/preference data
- admin/manual opportunity ingestion or controlled imports
- action loop for save / dismiss / apply or equivalent
- basic ranking and thresholding
We should not commit now to:
- large-scale multi-platform scraping across all listed sources
- employer portal phase
- full enrichment from every external source
- hourly scraping pipelines
- Travel Mode as a fully polished feature
### 3. Marketplace
We can deliver:
- provider profile model
- provider onboarding and admin approval flow
- service listings
- open browsing
- basic booking flow
- pathway-triggered recommendations in a simpler rules-based form
- basic booking states and notifications
We should not commit now to:
- outcome guarantee engine
- Q-Score verified provider performance system
- group demand aggregation engine
- pre-booking engine
- full dispute/refund automation
- complex commission and escrow logic
### 4. Social Branding
We can deliver:
- LinkedIn-first MVP
- persona selection / strategy mapping
- profile audit and rewrite suggestions
- content calendar generation
- draft generation with approval queue
- Brand Score v1 with limited inputs
- dashboard-level summary output
We should not commit now to:
- full 4-platform automation at launch
- enterprise social branding module
- auto-posting across all platforms
- engagement automation and response automation
- deep analytics or recruiter visibility measurement across platforms
## Proposed Delivery Sequence
### Week 1: Foundation and Pathways First
- freeze MVP scope across all four modules
- lock shared entities: user profile, pathway state, provider, opportunity, social profile, recommendation event
- define API contracts and handoff boundaries
- build Pathways questionnaire and generation flow first
- set up admin tooling where manual ops will replace automation in v1
**Why this first:** Pathways drives the recommendation layer for the other three services. If Pathways is unclear, Matchmaking, Marketplace, and Social Branding all drift.
### Week 2: Matchmaking and Marketplace Core
- implement opportunity ingestion and matching service
- build seeker feed and interaction loop
- build provider onboarding, listing, and booking flow
- wire simple pathway-triggered recommendations into Marketplace
- begin integration testing across Pathways -> Matchmaking / Marketplace
### Week 3: Social Branding, Stabilization, Testing, Handoff
- ship LinkedIn-first Social Branding flow
- connect Brand Score v1 back into user profile / recommendation logic
- complete end-to-end QA on all four services
- document APIs, states, payloads, and known gaps
- run handoff sessions with the downstream team
- close with bug fixes and release notes
## If We Need a 2-Week Version
The 2-week plan should be framed as **internal alpha only**.
That version would mean:
- Pathways only in a simplified form
- Matchmaking with manual opportunity data only
- Marketplace with browse + provider listing + request flow, not full booking depth
- Social Branding as strategy + draft generation only, no posting workflow
## First Thing We Should Do
The first step is **not coding features**. The first step is to lock the MVP cut line and architecture decisions.
Specifically:
- decide the exact v1 journey for each module
- identify what will be manual/admin-assisted in v1
- confirm data sources we actually have access to
- define what the handoff team expects from us: API-ready services, UI flows, docs, or tested modules
If we do not settle this in the first 1 to 2 days, the team will burn time building PRD breadth instead of delivering a stable product slice.
## Main Trade-Offs
- **Speed vs completeness:** We can deliver four working modules in 3 weeks only by shipping a narrow MVP.
- **Automation vs reliability:** Manual ingestion and admin workflows are acceptable for v1 if they reduce engineering risk.
- **Breadth vs polish:** It is better to have one good flow per module than many half-finished flows.
- **Platform ambition vs integration reality:** Several PRDs assume external platform access, scraping, analytics, and automation that may not be practical in the current window.
- **Feature depth vs handoff quality:** If we overbuild, testing and documentation will suffer, which will hurt the other team more than a smaller but stable release.
## Points to Raise in the Meeting
- Are we aligned that this is an MVP delivery, not full PRD completion?
- Is **Pathways Option A only** acceptable for this phase?
- For Matchmaking, are **manual/admin-loaded opportunities** acceptable for v1?
- For Marketplace, do we need **true booking and payment**, or is booking/request capture enough for phase 1?
- For Social Branding, is **LinkedIn-first** acceptable, with other platforms deferred?
- Which advanced features are explicitly deferred so they do not re-enter scope mid-sprint?
- What exactly does the receiving team need in the handoff?
- Who signs off on scope changes once delivery starts?
## Recommended Closing Statement
Our recommendation should be to commit to a **3-week MVP across all four modules**, with:
- Pathways as the orchestration anchor
- Matchmaking and Marketplace as operational core flows
- Social Branding as a LinkedIn-first managed MVP
- final days reserved for testing, documentation, and handoff
That gives us the best chance of delivering something credible, integrated, and supportable instead of spreading effort across too much PRD depth.

19
PRD_Portfolio_Summary.md Normal file
View File

@@ -0,0 +1,19 @@
# GrowQR PRD Portfolio Summary
This summary consolidates the major work described across the Pathways, Matchmaking, Marketplace, Social Branding, Courses, Assessment, Interview, and Roleplay PRDs. Together, these documents define GrowQR as an AI-led career development platform built around a central orchestration layer rather than a single tool. The platform's core promise is to understand a user's background, skills, preferences, and measured capabilities, then turn that into a dynamic pathway for growth, positioning, and opportunity.
At the center is **Pathways**, which acts as GrowQR's orchestration engine. Pathways takes profile data from LinkedIn or a resume, combines it with a structured questionnaire, and for premium users adds psychometric profiling and 25 Q-Scores. It then generates a set of career options across close-match, adjacent, and stretch paths, renders them in an interactive visual career web, and activates a time-bound development journey. Once a pathway is live, Pathways coordinates all 11 GrowQR services through weekly cycles with explicit rules around sequencing, time commitment, adaptation, and progression from learning to application. It also produces a branded Pathway Report that explains the user's archetype, skill gaps, job-market fit, and action plan.
Around this orchestration layer sits a set of execution services. The **Assessment Service** provides short, role-specific AI-generated assessments using a standardized input-processing-output model. It evaluates technical, behavioral, and role-fit signals, contributes directly to Q-Scores, and feeds recommendations into other services. The **Course Service** handles learning delivery through a staged strategy: first indexing external courses, then enabling third-party creators, and finally generating GrowQR-owned GenAI course IP personalized by persona, life stage, industry, and Q-Score profile. Both services deliberately avoid building a proprietary LMS and instead integrate with platforms such as Moodle and Thinkific.
The practice layer is covered by **Interview** and **Roleplay**. These are avatar-based AI simulations with real-time voice, video, and optional screen sharing. Interview focuses on mock interview performance across different interviewer personas, durations, and interview types. Roleplay focuses on applied communication and scenario-based performance. Both services analyze voice, body language, facial expression, technical quality, and, where relevant, screen content such as code or presentations. Both also feed their findings back into Courses, Assessment, and the Dashboard so users can move from diagnosis to practice to improvement.
The opportunity layer is defined by two closely related systems: the **Opportunity Matchmaking Engine** and the **Marketplace**. The Matchmaking Engine is a two-sided AI marketplace for jobs, gigs, events, advisory roles, surveys, temporary earning opportunities, and future-pathway opportunities. It matches users using 46 personalized attributes: 25 Q-Scores plus 20 stated preferences, with a weighted scoring model across skills, personality, culture, growth, and compensation. It also introduces a feedback loop in which actions such as apply, save, RSVP, or dismiss continuously refine future recommendations. A notable feature is Travel Mode, which temporarily expands location-aware opportunity discovery.
The Marketplace is the paid services supply layer for GrowQR. It houses validated providers such as coaches, senior users, institutions, and in-house experts across formats including 1:1 sessions, async reviews, workshops, retainers, and done-for-you services. Marketplace is separate from Mentors: Marketplace is the open verified supply pool, while Mentors is a curated subset surfaced by Pathways at the right cycle moments. The PRD goes beyond basic booking flows and introduces several structural innovations intended to solve cold-start and trust problems: seeding supply from GrowQR's own successful premium users, outcome-guarantee services tied to measurable results, Q-Score-verified provider performance, group-session demand aggregation from pathway signals, and pre-booking of future services based on predicted need.
The **Social Branding** service extends GrowQR from internal development to external market visibility. It automates professional brand building across LinkedIn, Instagram, X, and YouTube using a scrape-analyze-generate-approve-post-track loop. For individuals, the service builds a persona-led content system that combines a pre-baked toolkit with dynamic AI content, calculates a Brand Score, and feeds that score into RQx in the wider Q-Score model. For enterprises, it adds governance, content rules, multi-account structures, and brand voice controls. In effect, Social Branding turns reputation and discoverability into measurable, managed platform outputs rather than side effects.
Across all eight PRDs, several common design principles are consistent. First, GrowQR is designed as a **microservice ecosystem** where each service is specialized but tightly integrated through shared data and events. Second, the platform is built around **measurement and feedback**, especially through Q-Scores, Brand Score, and performance history. Third, GrowQR aims to move users from insight to action: discover strengths and gaps, practice them, learn targeted skills, improve measurable scores, strengthen market presence, and finally unlock better opportunities and providers. Fourth, the platform is intentionally **adaptive**. Recommendations, pathways, and provider suggestions are expected to change as users complete services and their scores improve.
In summary, the work described in these PRDs is not a collection of disconnected tools. It is a full-stack career growth operating system. Pathways determines direction, Assessments and simulations diagnose and build capability, Courses provide structured learning, Social Branding improves professional visibility, Matchmaking finds opportunities, and Marketplace connects users to verified human support. The unifying logic is that every meaningful user action should generate data, every data point should sharpen personalization, and every service should reinforce the others in a closed-loop career development system.

187
REPO_INVENTORY.md Normal file
View File

@@ -0,0 +1,187 @@
# GrowQR Repository Inventory
> Last updated: 2026-06-22
> This document catalogs every repository, branch, and remote in the GrowQR ecosystem.
---
## 📍 Quick Links
| Platform | Org | URL |
|---|---|---|
| **Gitea (Primary)** | `growqr-app` | https://git.openputer.com/growqr-app |
| **Gitea (Legacy)** | `puter` | https://git.openputer.com/puter |
| **GitHub** | `GrowQR-Code` | https://github.com/GrowQR-Code |
| **GitHub** | `Growqr-org` | https://github.com/Growqr-org |
| **GitHub** | `Prmsnls` | https://github.com/Prmsnls |
| **Docs** | `growqr-app/docs` | https://git.openputer.com/growqr-app/docs |
| **Linear** | `PRM` team | https://linear.app/prmsnls/team/PRM |
---
## 🟢 Active Repositories (In Development)
### 1. `growqr-backend` — Main API Backend
| | |
|---|---|
| **Description** | Core backend API: auth, users, missions, agents, events, orchestration, QScore integration |
| **Stack** | Node.js / TypeScript / Drizzle ORM / RivetKit / Express / tRPC |
| **Canonical Remote** | `https://git.openputer.com/puter/growqr-backend.git` |
| **Staging Branch** | **`staging-rosh`** ← active development |
| **Production Branch** | `main` |
| **Other Branches** | `staging`, `chore/release`, `service-rest-events`, `subagents-microservice`, `checkpoint/pre-mission-actions-20260606-031159` |
| **Mirror** | `https://github.com/GrowQR-Code/growqr-backend` (if exists) |
| **VPS Deploy** | `gqr-temp` (`/opt/growqr/growqr-backend`) |
| **Linear Issues** | PRM-41, PRM-42, PRM-6369 |
### 2. `growqr-dashboard` — Next.js Dashboard Frontend
| | |
|---|---|
| **Description** | Main user-facing dashboard: home, onboarding, missions, agents, QScore, analytics |
| **Stack** | Next.js 14 / React / TypeScript / Tailwind / shadcn |
| **Canonical Remote** | `https://git.openputer.com/puter/growqr-dashboard.git` |
| **Secondary Remote** | `dashboard-ui``https://github.com/GrowQR-Code/dashboard-ui.git` |
| **Staging Branch** | **`staging-rosh`** ← active development |
| **Production Branch** | `main` |
| **Other Branches** | `staging`, `prd-new-ui`, `dashboard-ui-mission-rebrand`, `backup/mission-action-queue-ui-20260605`, `checkpoint/pre-mission-actions-20260606-031159` |
| **VPS Deploy** | `gqr-temp` (`/opt/growqr/growqr-dashboard`) |
| **Linear Issues** | PRM-36, PRM-48, PRM-49, PRM-52, PRM-55, PRM-5662 |
### 3. `interview-service` — AI Interview Agent
| | |
|---|---|
| **Description** | Voice + text interview practice with AI avatars, LiveAvatar integration, scoring |
| **Stack** | Node.js / Python / FastAPI / WebSocket / LiveAvatar API |
| **Canonical Remote** | `gitea``https://git.openputer.com/growqr-app/interview-service.git` |
| **GitHub Remote** | `origin``https://github.com/GrowQR-Code/interview-service.git` |
| **Staging Branch** | **`staging`** |
| **Production Branch** | `main` |
| **Other Branches** | `dashboard-service-rest-integration`, `pr-1`, `pr-1-updated`, `q-score` |
| **VPS Deploy** | `gqr-temp` (port 18007) |
| **Linear Issues** | PRM-50 |
### 4. `roleplay-service` — AI Roleplay Agent
| | |
|---|---|
| **Description** | Roleplay scenarios for job prep, behavioral interviews, negotiation practice |
| **Stack** | Node.js / Python / FastAPI / WebSocket |
| **Canonical Remote** | `gitea``https://git.openputer.com/growqr-app/roleplay-service.git` |
| **GitHub Remote** | `origin``https://github.com/GrowQR-Code/roleplay-service.git` |
| **Staging Branch** | **`staging`** |
| **Production Branch** | `main` |
| **Other Branches** | `dashboard-service-rest-integration`, `feat/planning-edit-leaderboard-demo`, `pr-1-updated` |
| **VPS Deploy** | `gqr-temp` (port 18008) |
| **Linear Issues** | PRM-50 |
### 5. `qscore_service` — QScore Calculation Engine
| | |
|---|---|
| **Description** | QX Score computation, origination events, score delivery, analytics pipeline |
| **Stack** | Python / FastAPI / UV |
| **Canonical Remote** | `gitea``https://git.openputer.com/puter/qscore-service.git` |
| **GitHub Remotes** | `origin``https://github.com/GrowQR-Code/qscore-service.git`, `github``https://github.com/Prmsnls/QScore-service.git` |
| **Staging Branch** | **`staging`** |
| **Production Branch** | `main` |
| **Other Branches** | `admin-ui`, `feature/quotients-from-pillars` |
| **VPS Deploy** | `gqr-temp` (port 18009) |
| **Linear Issues** | PRM-45, PRM-69 |
### 6. `growqr-app` — Legacy Monorepo (Partial)
| | |
|---|---|
| **Description** | Legacy monorepo containing dashboard-service, frontend, orchestrator, resume-builder, user-service, social-branding, nginx, scripts |
| **Stack** | Mixed (Next.js, Node.js, Python) |
| **Canonical Remote** | `gitea``https://git.openputer.com/growqr-app/growqr-app.git` |
| **GitHub Remote** | `origin``https://github.com/GrowQR-Code/growqr-app` |
| **Staging Branch** | **`staging`** |
| **Production Branch** | `main` |
| **Other Branches** | `dashboard-service-rest-integration`, `migration/legacy-to-contract`, `pr-1` |
| **Subdirectories** | `dashboard-service`, `frontend`, `orchestrator`, `resume-builder`, `user-service`, `social-branding`, `nginx`, `scripts` |
| **Linear Issues** | PRM-41, PRM-42, PRM-46 |
### 7. `agent-social-branding` — Social Branding Agent
| | |
|---|---|
| **Description** | LinkedIn content generation, brand score, personal branding pipeline |
| **Stack** | Python / FastAPI |
| **Canonical Remote** | `gitea``https://git.openputer.com/growqr-app/agent-social-branding.git` |
| **GitHub Remote** | `origin``https://github.com/Growqr-org/agent-social-branding` |
| **Active Branch** | **`main`** |
| **Other Branches** | `feature-update`, `handoff-phase-1` |
| **Linear Issues** | PRM-70 |
### 8. `docs` — Project Documentation (This Repo)
| | |
|---|---|
| **Description** | Central documentation hub: runbooks, architecture, PRDs, playbooks, meeting notes |
| **Canonical Remote** | `https://git.openputer.com/growqr-app/docs.git` |
| **Active Branch** | **`main`** |
---
## 🟡 Archived / Deferred Repositories
> Located in `/archived/`. These are not actively deployed but retain code history.
| Repo | Description | Gitea Remote | GitHub Remote | Active Branch |
|---|---|---|---|---|
| `assessment-service` | Skills assessment & quiz engine | `growqr-app/assessment-service` | `GrowQR-Code/assessments` | `feature/autocourse-pipeline` |
| `courses_service` | Course content & video delivery | `growqr-app/courses_service` | `GrowQR-Code/courses` | `feature/autocourse-pipeline` |
| `growqr-next-frontend` | Earlier Next.js dashboard iteration | `puter/growqr-next-frontend` | `GrowQR-Code/workflows--dashboard` | `main` |
| `marketplace-service` | Job marketplace / gig board | `growqr-app/marketplace-service` | `GrowQR-Code/marketplace` | `main` |
| `matchmaking-service` | Job-candidate matching engine | `growqr-app/matchmaking-service` | `GrowQR-Code/matchmaking` | `main` / `feat/matchmaking-scraping` |
| `pathways-service` | Career pathway recommendations | `growqr-app/pathways-service` | `GrowQR-Code/pathways` | `main` / `pr-1-review` |
---
## 🌐 Staging Environment (VPS `gqr-temp`)
| Service | Local Port | Public URL | Docker Project |
|---|---|---|---|
| Dashboard | 13000 | `https://dashboard-staging.gqr.puter.wtf` | `growqr-dashboard-staging` |
| Backend API | 18012 | `https://backend-staging.gqr.puter.wtf` | `growqr-backend-staging` |
| Backend Gitea | 13001 | `https://backend-gitea-staging.gqr.puter.wtf` | `growqr-backend-staging` |
| Interview Service | 18007 | `https://interview-staging.gqr.puter.wtf` | `interview-service-staging` |
| Roleplay Service | 18008 | `https://roleplay-staging.gqr.puter.wtf` | `roleplay-service-staging` |
| QScore Service | 18009 | `https://qscore-staging.gqr.puter.wtf` | `qscore-service-staging` |
| Resume Builder | 18010 | `https://resume-staging.gqr.puter.wtf` | `resume-builder-staging` |
| User Service | 18011 | `https://user-staging.gqr.puter.wtf` | `user-service-staging` |
| Rivet Engine | 1642021 | Internal | `growqr-backend-staging` |
**VPS IP:** `168.144.123.127` (Debian 13)
**Deploy Root:** `/opt/growqr/`
**Caddyfile:** `/etc/caddy/Caddyfile`
---
## 🏷️ Branch Naming Conventions
| Prefix | Meaning |
|---|---|
| `main` | Production-ready code |
| `staging` | Pre-production integration branch |
| `staging-rosh` | **Active feature development branch** (backend + dashboard) |
| `feat/*` | Feature branches |
| `chore/*` | Maintenance / tooling |
| `checkpoint/*` | Pre-change snapshots with timestamp |
| `backup/*` | Manual backup branches |
| `migration/*` | Legacy-to-new migration work |
---
## 🔄 Sync Workflow
1. **Local dev** → commit to `staging-rosh` (backend/dashboard) or `staging` (services)
2. **Push** to Gitea origin
3. **VPS** pulls via Git credential store (`~/.git-credentials`)
4. **Docker compose** restart on VPS for deploy
5. **No SCP/tar** — all sync is Git-based
---
## 📋 Related Linear Resources
- **Team:** PRM (Prmsnls)
- **Project:** [GrowQR](https://linear.app/prmsnls/project/growqr)
- **Current Sprint Issues:** PRM-56 through PRM-70
- **Members:** puter, divyansh242805, karthiksaiketha, kirti

BIN
UI design Mockup Draft.pptx Normal file

Binary file not shown.

View File

@@ -0,0 +1,89 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>GrowQR — Linear System Flow</title>
<style>
:root {
--bg:#080c14; --panel:#101827; --card:#162132; --card2:#111a28; --border:#26364d;
--text:#e5edf8; --muted:#92a3b8; --blue:#60a5fa; --purple:#a78bfa; --green:#34d399;
--amber:#fbbf24; --rose:#fb7185; --cyan:#22d3ee; --line:#52647c;
}
*{box-sizing:border-box;margin:0;padding:0}
body{min-height:100vh;background:radial-gradient(circle at top,#121a2b 0,#080c14 55%);color:var(--text);font-family:Inter,-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif;padding:42px 28px 70px}
header{text-align:center;margin-bottom:32px}
h1{font-size:2.35rem;letter-spacing:-.04em;margin-bottom:10px}.grad{background:linear-gradient(135deg,var(--blue),var(--purple),var(--cyan));-webkit-background-clip:text;color:transparent}
header p{color:var(--muted);font-size:1.05rem;max-width:860px;margin:auto;line-height:1.55}
.shell{max-width:1480px;margin:0 auto;background:rgba(16,24,39,.82);border:1px solid var(--border);border-radius:22px;padding:32px;box-shadow:0 24px 90px rgba(0,0,0,.45);position:relative;overflow:hidden}
.shell:before{content:"";position:absolute;inset:0;background:linear-gradient(90deg,rgba(96,165,250,.06),transparent 18%,transparent 82%,rgba(251,191,36,.05));pointer-events:none}
.legend{display:flex;gap:14px;flex-wrap:wrap;justify-content:center;margin-bottom:30px;position:relative;z-index:2}.pill{border:1px solid var(--border);background:#0d1421;border-radius:999px;padding:8px 13px;color:var(--muted);font-size:.78rem}.dot{display:inline-block;width:9px;height:9px;border-radius:50%;margin-right:7px}
.flow{position:relative;z-index:2;display:grid;grid-template-columns:repeat(8,minmax(135px,1fr));gap:14px;align-items:stretch;margin-bottom:32px}
.step{background:linear-gradient(180deg,var(--card),var(--card2));border:1px solid var(--border);border-radius:16px;padding:18px 16px;min-height:220px;position:relative;box-shadow:0 12px 26px rgba(0,0,0,.18)}
.step:after{content:"→";position:absolute;right:-17px;top:50%;transform:translateY(-50%);color:var(--line);font-size:25px;font-weight:700;z-index:3}.step:last-child:after{display:none}
.num{width:28px;height:28px;border-radius:9px;display:flex;align-items:center;justify-content:center;font-weight:800;font-size:.8rem;margin-bottom:12px;background:rgba(255,255,255,.06);border:1px solid var(--border)}
.step h3{font-size:.98rem;margin-bottom:10px;line-height:1.25}.step p{font-size:.79rem;color:var(--muted);line-height:1.45;margin-bottom:12px}.step ul{list-style:none;color:var(--muted);font-size:.76rem;line-height:1.65}.step li{display:flex;gap:7px}.step li:before{content:"•";opacity:.65}.blue{border-color:rgba(96,165,250,.36)}.blue .num{color:var(--blue);background:rgba(96,165,250,.12)}.purple{border-color:rgba(167,139,250,.38)}.purple .num{color:var(--purple);background:rgba(167,139,250,.12)}.green{border-color:rgba(52,211,153,.36)}.green .num{color:var(--green);background:rgba(52,211,153,.12)}.amber{border-color:rgba(251,191,36,.38)}.amber .num{color:var(--amber);background:rgba(251,191,36,.12)}.rose{border-color:rgba(251,113,133,.36)}.rose .num{color:var(--rose);background:rgba(251,113,133,.12)}.cyan{border-color:rgba(34,211,238,.36)}.cyan .num{color:var(--cyan);background:rgba(34,211,238,.12)}
.swimlanes{position:relative;z-index:2;display:grid;grid-template-columns:1.05fr 1.25fr 1.15fr;gap:18px;margin-top:24px}.lane{border:1px solid var(--border);border-radius:16px;background:rgba(13,20,33,.75);padding:20px}.lane h2{font-size:1rem;margin-bottom:14px}.lane-row{display:flex;gap:12px;align-items:flex-start;padding:12px 0;border-top:1px solid rgba(38,54,77,.75)}.lane-row:first-of-type{border-top:0}.badge{min-width:88px;font-size:.72rem;text-transform:uppercase;letter-spacing:.08em;color:var(--muted)}.lane-row div:last-child{font-size:.82rem;color:var(--text);line-height:1.45}.muted{color:var(--muted)}
.callouts{position:relative;z-index:2;display:grid;grid-template-columns:repeat(4,1fr);gap:14px;margin-top:18px}.callout{background:#0d1421;border:1px solid var(--border);border-radius:14px;padding:16px}.callout h4{font-size:.86rem;margin-bottom:8px}.callout p{font-size:.76rem;color:var(--muted);line-height:1.45}
footer{text-align:center;color:var(--muted);font-size:.78rem;margin-top:28px}
@media(max-width:1200px){.flow{grid-template-columns:repeat(4,1fr)}.step:nth-child(4):after{content:"↓";right:50%;top:auto;bottom:-24px}.step:nth-child(5):before{content:""}.swimlanes,.callouts{grid-template-columns:1fr 1fr}}
@media(max-width:760px){body{padding:24px 14px}.shell{padding:20px}.flow,.swimlanes,.callouts{grid-template-columns:1fr}.step:after{content:"↓";right:50%;top:auto;bottom:-24px}.step:last-child:after{display:none}}
</style>
</head>
<body>
<header>
<h1><span class="grad">GrowQR</span> End-to-End System Flow</h1>
<p>A linear view of how a user request moves through the product: from interactive client, through auth and durable agent orchestration, into sandboxed execution, domain tools, versioned memory, and back to the UI.</p>
</header>
<div class="shell">
<div class="legend">
<span class="pill"><span class="dot" style="background:var(--blue)"></span>Client / Gateway</span>
<span class="pill"><span class="dot" style="background:var(--purple)"></span>Durable Control</span>
<span class="pill"><span class="dot" style="background:var(--green)"></span>Runtime Execution</span>
<span class="pill"><span class="dot" style="background:var(--cyan)"></span>Domain Tools</span>
<span class="pill"><span class="dot" style="background:var(--amber)"></span>Versioned Memory</span>
<span class="pill"><span class="dot" style="background:var(--rose)"></span>System DB</span>
</div>
<section class="flow">
<article class="step blue"><div class="num">1</div><h3>User Interaction</h3><p>User opens a channel, thread, quest, or agent module.</p><ul><li>Chat-first interface</li><li>Generated UI cards</li><li>Realtime progress surface</li></ul></article>
<article class="step blue"><div class="num">2</div><h3>Gateway Bootstrap</h3><p>Stateless backend validates identity and prepares the session.</p><ul><li>Auth/session verification</li><li>Billing/entitlement checks</li><li>Repo + actor lookup</li></ul></article>
<article class="step purple"><div class="num">3</div><h3>Actor Connection</h3><p>Client connects to the durable control plane for live orchestration.</p><ul><li>WebSocket event stream</li><li>Actor key routing</li><li>Per-user state hydration</li></ul></article>
<article class="step purple"><div class="num">4</div><h3>Intent Routing</h3><p>The control plane maps intent to a thread, quest workflow, or specialized agent.</p><ul><li>Thread/session state</li><li>Quest workflow state</li><li>Runtime lifecycle decision</li></ul></article>
<article class="step green"><div class="num">5</div><h3>Sandbox Startup</h3><p>An isolated execution environment is created or resumed.</p><ul><li>Per-user/runtime isolation</li><li>Workspace/worktree mount</li><li>Agent harness session</li></ul></article>
<article class="step green"><div class="num">6</div><h3>Agent Execution</h3><p>The runtime performs reasoning, tool selection, file operations, and progress streaming.</p><ul><li>Sub-agent delegation</li><li>File/read/write/bash tools</li><li>Incremental UI events</li></ul></article>
<article class="step cyan"><div class="num">7</div><h3>Domain Tool Calls</h3><p>Existing services are invoked as controlled tools, not as direct frontend destinations.</p><ul><li>Interview / Roleplay</li><li>Pathways / Q-Score</li><li>Social & matching tools</li></ul></article>
<article class="step amber"><div class="num">8</div><h3>Memory Commit</h3><p>Outputs become versioned memory and indexed system metadata.</p><ul><li>Markdown/JSON memory files</li><li>Diff, commit, merge</li><li>DB pointers + indexes</li></ul></article>
</section>
<section class="swimlanes">
<div class="lane">
<h2 class="blue">Request Path</h2>
<div class="lane-row"><span class="badge">Initial</span><div>Client calls the gateway for auth, provisioning, and actor connection details.</div></div>
<div class="lane-row"><span class="badge">Realtime</span><div>Client then communicates with the durable control plane over live events/actions.</div></div>
<div class="lane-row"><span class="badge">Return</span><div>Progress, tool activity, generated UI modules, and final artifacts stream back to the client.</div></div>
</div>
<div class="lane">
<h2 class="purple">Control Responsibilities</h2>
<div class="lane-row"><span class="badge">Actors</span><div>Hold small durable state: active threads, quest runs, runtime handles, recovery pointers.</div></div>
<div class="lane-row"><span class="badge">Workflow</span><div>Serialize long-running work, resume after restarts, coordinate runtime and memory commits.</div></div>
<div class="lane-row"><span class="badge">Security</span><div>Control which user, actor, runtime, repo, and service calls are allowed.</div></div>
</div>
<div class="lane">
<h2 class="green">Execution & Persistence</h2>
<div class="lane-row"><span class="badge">Runtime</span><div>Ephemeral sandbox runs the agent harness and tool execution. It can be killed/restarted.</div></div>
<div class="lane-row"><span class="badge">Memory</span><div>Git-backed files are the durable user memory and audit trail.</div></div>
<div class="lane-row"><span class="badge">DB</span><div>Relational storage keeps product metadata, indexes, recovery pointers, and billing/account records.</div></div>
</div>
</section>
<section class="callouts">
<div class="callout"><h4 class="purple">Why actors?</h4><p>They provide durable, addressable entities for users, threads, quests, runtimes, and score updates without rebuilding locking and recovery in the gateway.</p></div>
<div class="callout"><h4 class="green">Why sandbox?</h4><p>Agent execution can run file tools, shell commands, plugins, and service calls in an isolated, disposable runtime.</p></div>
<div class="callout"><h4 class="amber">Why Git memory?</h4><p>User context becomes inspectable, versioned, diffable, reversible, and portable across runtime restarts and upgrades.</p></div>
<div class="callout"><h4 class="rose">Why DB too?</h4><p>The database is not the agent memory. It is the operational index for accounts, pointers, subscriptions, recovery, and fast dashboard queries.</p></div>
</section>
</div>
<footer>GrowQR — Linear architecture flow · Client → Gateway → Durable Control → Sandbox Runtime → Tools → Memory → UI</footer>
</body>
</html>

650
architecture-diagram.html Normal file
View File

@@ -0,0 +1,650 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>GrowQR — System Architecture</title>
<style>
:root {
--bg: #0b0f17;
--surface: #111827;
--surface-2: #1a2332;
--border: #1f2d3d;
--border-light: #2d3f54;
--text: #e2e8f0;
--text-dim: #94a3b8;
--accent-blue: #60a5fa;
--accent-purple: #a78bfa;
--accent-green: #34d399;
--accent-amber: #fbbf24;
--accent-rose: #fb7185;
--accent-cyan: #22d3ee;
--line: #334155;
--line-active: #60a5fa;
}
* { box-sizing: border-box; margin: 0; padding: 0; }
body {
background: var(--bg);
color: var(--text);
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
min-height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
padding: 48px 24px 80px;
}
header {
text-align: center;
margin-bottom: 48px;
}
header h1 {
font-size: 2.4rem;
font-weight: 700;
letter-spacing: -0.03em;
margin-bottom: 8px;
}
header h1 span {
background: linear-gradient(135deg, var(--accent-blue), var(--accent-purple));
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
header p {
color: var(--text-dim);
font-size: 1.05rem;
}
.legend {
display: flex;
gap: 24px;
flex-wrap: wrap;
justify-content: center;
margin-bottom: 40px;
}
.legend-item {
display: flex;
align-items: center;
gap: 8px;
font-size: 0.85rem;
color: var(--text-dim);
}
.legend-dot {
width: 12px;
height: 12px;
border-radius: 3px;
}
.diagram-wrapper {
position: relative;
width: 100%;
max-width: 1200px;
background: var(--surface);
border: 1px solid var(--border);
border-radius: 16px;
padding: 48px 40px 56px;
box-shadow: 0 20px 60px rgba(0,0,0,0.4);
}
/* SVG arrows layer */
.arrows-svg {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
pointer-events: none;
z-index: 0;
}
.arrows-svg path {
fill: none;
stroke: var(--line);
stroke-width: 1.5;
transition: stroke 0.3s;
}
.arrows-svg marker path {
fill: var(--line);
stroke: none;
transition: fill 0.3s;
}
/* Grid layout */
.grid {
position: relative;
z-index: 1;
display: grid;
grid-template-columns: 280px 1fr 280px;
grid-template-rows: auto auto auto auto;
gap: 36px 48px;
align-items: start;
}
.col-left { grid-column: 1; }
.col-center { grid-column: 2; }
.col-right { grid-column: 3; }
.row-1 { grid-row: 1; }
.row-2 { grid-row: 2; }
.row-3 { grid-row: 3; }
.row-4 { grid-row: 4; }
/* Group (cluster) boxes */
.group {
border: 1px solid var(--border-light);
border-radius: 12px;
padding: 20px 20px 16px;
position: relative;
background: rgba(17,24,39,0.7);
backdrop-filter: blur(4px);
}
.group-label {
position: absolute;
top: -10px;
left: 16px;
background: var(--surface);
padding: 0 10px;
font-size: 0.7rem;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 0.08em;
color: var(--text-dim);
border-radius: 4px;
}
/* Node cards */
.node {
background: var(--surface-2);
border: 1px solid var(--border);
border-radius: 10px;
padding: 16px 18px;
transition: transform 0.2s, border-color 0.2s, box-shadow 0.2s;
cursor: default;
}
.node:hover {
transform: translateY(-2px);
border-color: var(--border-light);
box-shadow: 0 8px 24px rgba(0,0,0,0.3);
}
.node h3 {
font-size: 0.95rem;
font-weight: 600;
margin-bottom: 10px;
display: flex;
align-items: center;
gap: 8px;
}
.node h3 .icon {
width: 22px;
height: 22px;
border-radius: 5px;
display: inline-flex;
align-items: center;
justify-content: center;
font-size: 0.75rem;
}
.node ul {
list-style: none;
font-size: 0.82rem;
color: var(--text-dim);
line-height: 1.7;
}
.node ul li {
display: flex;
align-items: center;
gap: 8px;
}
.node ul li::before {
content: "";
width: 5px;
height: 5px;
border-radius: 50%;
background: var(--text-dim);
opacity: 0.5;
flex-shrink: 0;
}
.node .meta {
margin-top: 10px;
padding-top: 10px;
border-top: 1px solid var(--border);
font-size: 0.75rem;
color: var(--text-dim);
display: flex;
justify-content: space-between;
}
/* Color accents */
.accent-blue { color: var(--accent-blue); }
.accent-purple { color: var(--accent-purple); }
.accent-green { color: var(--accent-green); }
.accent-amber { color: var(--accent-amber); }
.accent-rose { color: var(--accent-rose); }
.accent-cyan { color: var(--accent-cyan); }
.bg-blue { background: rgba(96,165,250,0.12); }
.bg-purple { background: rgba(167,139,250,0.12); }
.bg-green { background: rgba(52,211,153,0.12); }
.bg-amber { background: rgba(251,191,36,0.12); }
.bg-rose { background: rgba(251,113,133,0.12); }
.bg-cyan { background: rgba(34,211,238,0.12); }
.border-blue { border-color: rgba(96,165,250,0.25); }
.border-purple { border-color: rgba(167,139,250,0.25); }
.border-green { border-color: rgba(52,211,153,0.25); }
.border-amber { border-color: rgba(251,191,36,0.25); }
.border-rose { border-color: rgba(251,113,133,0.25); }
.border-cyan { border-color: rgba(34,211,238,0.25); }
/* Special large center node */
.node-center {
text-align: center;
padding: 24px 28px;
}
.node-center h3 {
justify-content: center;
font-size: 1.1rem;
margin-bottom: 14px;
}
.node-center .sub-nodes {
display: flex;
gap: 12px;
justify-content: center;
flex-wrap: wrap;
}
.sub-node {
background: var(--surface);
border: 1px solid var(--border);
border-radius: 8px;
padding: 10px 16px;
font-size: 0.8rem;
font-weight: 500;
color: var(--text-dim);
}
/* DB bar */
.db-bar {
grid-column: 1 / -1;
justify-self: center;
display: flex;
align-items: center;
gap: 16px;
background: var(--surface-2);
border: 1px solid var(--border);
border-radius: 12px;
padding: 18px 32px;
min-width: 380px;
justify-content: center;
}
.db-bar .icon {
width: 36px;
height: 36px;
border-radius: 8px;
display: flex;
align-items: center;
justify-content: center;
font-size: 1.1rem;
}
.db-bar h3 {
font-size: 1rem;
font-weight: 600;
}
.db-bar .tech {
font-size: 0.8rem;
color: var(--text-dim);
}
/* External services row */
.externals {
display: flex;
gap: 12px;
justify-content: center;
}
.ext-pill {
background: var(--surface-2);
border: 1px solid var(--border);
border-radius: 8px;
padding: 10px 16px;
font-size: 0.8rem;
display: flex;
align-items: center;
gap: 8px;
color: var(--text-dim);
}
/* Arrow labels */
.arrow-label {
position: absolute;
background: var(--surface);
border: 1px solid var(--border);
border-radius: 6px;
padding: 3px 10px;
font-size: 0.7rem;
color: var(--text-dim);
z-index: 2;
white-space: nowrap;
}
/* Responsive */
@media (max-width: 1000px) {
.grid {
grid-template-columns: 1fr 1fr;
gap: 24px;
}
.col-left, .col-center, .col-right { grid-column: auto; }
.node-center { grid-column: 1 / -1; }
.db-bar { grid-column: 1 / -1; min-width: unset; width: 100%; }
}
@media (max-width: 640px) {
.grid { grid-template-columns: 1fr; }
.diagram-wrapper { padding: 28px 20px; }
header h1 { font-size: 1.6rem; }
}
/* Print */
@media print {
body { background: white; color: black; }
.diagram-wrapper { box-shadow: none; border: 1px solid #ccc; }
}
</style>
</head>
<body>
<header>
<h1><span>GrowQR</span> System Architecture</h1>
<p>Durable Agent-centric architecture with RivetKit actors, OpenCode runtime &amp; Git-backed memory</p>
</header>
<div class="legend">
<div class="legend-item"><div class="legend-dot bg-blue"></div>Frontend / BFF</div>
<div class="legend-item"><div class="legend-dot bg-purple"></div>Control Plane (Actors)</div>
<div class="legend-item"><div class="legend-dot bg-green"></div>Runtime / Execution</div>
<div class="legend-item"><div class="legend-dot bg-amber"></div>Memory / Storage</div>
<div class="legend-item"><div class="legend-dot bg-rose"></div>Database</div>
<div class="legend-item"><div class="legend-dot bg-cyan"></div>External Services</div>
</div>
<div class="diagram-wrapper">
<!-- SVG Layer for arrows -->
<svg class="arrows-svg" id="arrowsSvg">
<defs>
<marker id="arr" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="6" markerHeight="6" orient="auto-start-reverse">
<path d="M 0 0 L 10 5 L 0 10 z" />
</marker>
<marker id="arr-active" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="6" markerHeight="6" orient="auto-start-reverse">
<path d="M 0 0 L 10 5 L 0 10 z" fill="#60a5fa" />
</marker>
</defs>
</svg>
<div class="grid" id="grid">
<!-- Row 1 -->
<div class="col-left row-1">
<div class="group border-blue">
<div class="group-label accent-blue">Frontend</div>
<div class="node border-blue" id="node-ui">
<h3><span class="icon bg-blue accent-blue"></span>React UI</h3>
<ul>
<li>Conversational interface</li>
<li>Real-time updates</li>
</ul>
</div>
<div style="height:12px"></div>
<div class="node border-blue" id="node-nextjs">
<h3><span class="icon bg-blue accent-blue"></span>Next.js BFF</h3>
<ul>
<li>Auth &amp; session management</li>
<li>Payments webhooks</li>
<li>Actor management proxy</li>
</ul>
<div class="meta">
<span>Vercel / OpenNext</span>
<span class="accent-blue">BFF Layer</span>
</div>
</div>
</div>
<div style="height:14px"></div>
<div class="externals">
<div class="ext-pill" id="node-clerk">
<span class="accent-cyan">🔐</span> Clerk Auth
</div>
<div class="ext-pill" id="node-stripe">
<span class="accent-cyan">💳</span> Stripe
</div>
</div>
</div>
<div class="col-center row-1 row-2">
<div class="node node-center border-purple" id="node-actor">
<h3><span class="icon bg-purple accent-purple"></span>Actor Backend — RivetKit</h3>
<div class="sub-nodes">
<div class="sub-node">Actor Runner</div>
<div class="sub-node">Actor Engine</div>
<div class="sub-node">Actor Storage</div>
</div>
<div style="margin-top:12px; font-size:0.8rem; color:var(--text-dim);">
Durable control plane — manages lifecycle, routing &amp; state
</div>
</div>
</div>
<div class="col-right row-1">
<div class="group border-green">
<div class="group-label accent-green">Sandboxed Runtime</div>
<div class="node border-green" id="node-runtime">
<h3><span class="icon bg-green accent-green"></span>Agent Runtime</h3>
<ul>
<li>Sub-agent orchestration</li>
<li>Skills loading</li>
<li>Tool execution</li>
<li>Dockerized isolation</li>
</ul>
<div class="meta">
<span>OpenCode / Container</span>
<span class="accent-green">Per-user sandbox</span>
</div>
</div>
</div>
</div>
<!-- Row 2 -->
<div class="col-left row-2"></div>
<div class="col-right row-2">
<div class="group border-amber">
<div class="group-label accent-amber">Git Memory</div>
<div class="node border-amber" id="node-git">
<h3><span class="icon bg-amber accent-amber"></span>Users Repos</h3>
<ul>
<li>Profile &amp; goals</li>
<li>Quest history</li>
<li>Channel memory</li>
<li>Artifact storage</li>
</ul>
<div class="meta">
<span>Git worktrees</span>
<span class="accent-amber">Source of truth</span>
</div>
</div>
</div>
</div>
<!-- Row 3 -->
<div class="col-left row-3"></div>
<div class="col-center row-3">
<div style="display:flex; gap:20px; justify-content:center;">
<div class="node border-purple" style="min-width:160px; text-align:center;" id="node-threads">
<h3 style="justify-content:center;"><span class="icon bg-purple accent-purple">🧵</span>Threads API</h3>
<ul style="text-align:left;">
<li>Session tracking</li>
<li>Message logs</li>
</ul>
</div>
<div class="node border-purple" style="min-width:160px; text-align:center;" id="node-memory">
<h3 style="justify-content:center;"><span class="icon bg-purple accent-purple">🧠</span>Memory API</h3>
<ul style="text-align:left;">
<li>Tracking memory</li>
<li>3-layer memory model</li>
</ul>
</div>
</div>
</div>
<div class="col-right row-3"></div>
<!-- Row 4 -->
<div class="col-left row-4"></div>
<div class="col-center row-4">
<div class="db-bar border-rose" id="node-db">
<div class="icon bg-rose accent-rose">🗄</div>
<div>
<h3>PostgreSQL <span style="color:var(--text-dim); font-weight:400;">/</span> AWS RDS</h3>
<div class="tech">Account metadata · Recovery pointers · Operational indexes</div>
</div>
</div>
</div>
<div class="col-right row-4"></div>
</div>
</div>
<footer style="margin-top: 40px; color: var(--text-dim); font-size: 0.8rem; text-align: center;">
GrowQR Architecture — Agent-centric · Git-backed · RivetKit-durable
</footer>
<script>
// Arrow drawing system
const svg = document.getElementById('arrowsSvg');
const grid = document.getElementById('grid');
function getCenter(el) {
const rect = el.getBoundingClientRect();
const wrap = document.querySelector('.diagram-wrapper').getBoundingClientRect();
return {
x: rect.left + rect.width / 2 - wrap.left,
y: rect.top + rect.height / 2 - wrap.top,
top: rect.top - wrap.top,
bottom: rect.bottom - wrap.top,
left: rect.left - wrap.left,
right: rect.right - wrap.left,
width: rect.width,
height: rect.height
};
}
function edgePoint(from, to, target='to') {
const dx = to.x - from.x;
const dy = to.y - from.y;
const angle = Math.atan2(dy, dx);
const ref = target === 'to' ? to : from;
const hw = ref.width / 2;
const hh = ref.height / 2;
// intersection with rectangle
const tan = Math.tan(angle);
let ix, iy;
if (Math.abs(dx) * hh > Math.abs(dy) * hw) {
ix = hw * Math.sign(dx);
iy = ix * tan;
} else {
iy = hh * Math.sign(dy);
ix = iy / (tan || 1e-9);
}
return { x: ref.x + ix, y: ref.y + iy };
}
function drawArrow(fromId, toId, label='', options={}) {
const fromEl = document.getElementById(fromId);
const toEl = document.getElementById(toId);
if (!fromEl || !toEl) return;
const from = getCenter(fromEl);
const to = getCenter(toEl);
const p1 = edgePoint(from, to, 'from');
const p2 = edgePoint(from, to, 'to');
let d;
if (options.straight) {
d = `M ${p1.x} ${p1.y} L ${p2.x} ${p2.y}`;
} else if (options.curve === 'vertical') {
const midY = (p1.y + p2.y) / 2;
d = `M ${p1.x} ${p1.y} C ${p1.x} ${midY}, ${p2.x} ${midY}, ${p2.x} ${p2.y}`;
} else {
const midX = (p1.x + p2.x) / 2;
d = `M ${p1.x} ${p1.y} C ${midX} ${p1.y}, ${midX} ${p2.y}, ${p2.x} ${p2.y}`;
}
const path = document.createElementNS('http://www.w3.org/2000/svg', 'path');
path.setAttribute('d', d);
path.setAttribute('marker-end', 'url(#arr)');
svg.appendChild(path);
if (label) {
const mid = { x: (p1.x + p2.x) / 2, y: (p1.y + p2.y) / 2 };
// simple adjustment to avoid overlapping
const lx = mid.x + (options.labelDx || 0);
const ly = mid.y + (options.labelDy || 0);
const lbl = document.createElement('div');
lbl.className = 'arrow-label';
lbl.textContent = label;
lbl.style.left = lx + 'px';
lbl.style.top = ly + 'px';
lbl.style.transform = 'translate(-50%, -50%)';
document.querySelector('.diagram-wrapper').appendChild(lbl);
}
}
function renderArrows() {
// Clear existing paths
svg.querySelectorAll('path:not(defs path)').forEach(p => p.remove());
document.querySelectorAll('.arrow-label').forEach(l => l.remove());
// Frontend -> Threads API
drawArrow('node-ui', 'node-threads', 'read/write');
// Frontend -> Actor Backend
drawArrow('node-nextjs', 'node-actor', 'RPC');
// Actor Backend -> Runtime
drawArrow('node-actor', 'node-runtime', 'spawn / exec');
// Actor Backend -> Threads API
drawArrow('node-actor', 'node-threads', 'manage');
// Actor Backend -> Memory API
drawArrow('node-actor', 'node-memory', 'track');
// Actor Backend -> DB
drawArrow('node-actor', 'node-db', 'persist');
// Memory API -> Git
drawArrow('node-memory', 'node-git', 'commit / diff');
// Git -> DB
drawArrow('node-git', 'node-db', 'sync pointers');
// Next.js -> Clerk
drawArrow('node-nextjs', 'node-clerk', 'auth', {straight:true, labelDy:-14});
// Next.js -> Stripe
drawArrow('node-nextjs', 'node-stripe', 'billing', {straight:true, labelDy:-14});
}
// Render on load and resize
window.addEventListener('load', renderArrows);
window.addEventListener('resize', () => { requestAnimationFrame(renderArrows); });
</script>
</body>
</html>

582
business architecture.md Normal file
View File

@@ -0,0 +1,582 @@
I read the workflow catalog docs. My understanding is:
GrowQR is not just “chat + resume + interview.” It should be a **career workflow platform** where users buy concrete outcomes:
- “Help me convert this interview into an offer.”
- “Help me switch careers.”
- “Help me negotiate salary.”
- “Help me become promotion-ready.”
- “Help me build my public professional brand.”
- “Help me become placement-ready / first-job-ready.”
The workflows are the **sellable products**.
The services, agents, OpenCode, Gitea, Q Score, matching, etc. are the **execution engine behind those products**.
## 1. Core product framing
The cleanest framing is:
> GrowQR is a gamified career operating system where every user has a living career identity, a readiness score, an AI agent squad, version-controlled career memory, and workflows that move them toward real-world outcomes.
For students, freshers, job seekers, and early professionals, the product should feel like:
- a career game,
- a guided mission system,
- an agent squad helping them,
- a visual progress map,
- a score they can improve,
- and a set of outputs they can actually use: resume, LinkedIn, interview answers, negotiation scripts, opportunity matches, promotion packet, etc.
Not a boring dashboard. Not a document-heavy SaaS tool.
## 2. The main architecture idea
There should be five major layers:
```txt
Frontend / UX
Backend API / Product Control Plane
Workflow Orchestration Layer
Agent + Service Execution Layer
Memory / Identity / Score / Matching Layer
```
More concretely:
```txt
Next.js Frontend
- workflow discovery
- career dashboard
- chat/agent UI
- game-like progress
- artifacts and score UI
GrowQR Backend
- auth
- users
- workflow catalog
- workflow runs
- billing/entitlements
- API gateway
- service adapters
- OpenCode lifecycle control
- Gitea/repo control
Rivet Actors / Workflows
- durable user actor
- durable workflow runs
- retries
- step execution
- human approval gates
- long-running background tasks
OpenCode Containers
- per-user agent runtime
- reads/writes user workspace
- generates artifacts
- runs agent prompts/modules
- commits memory/artifacts to Git
Gitea / Git-backed Memory
- user career repo
- artifacts
- conversations
- workflow state snapshots
- versioned resumes/profiles/scripts
- long-term career memory
Domain Services
- Interview service
- Roleplay service
- Q Score service
- Matchmaking service
- Social branding service
- Resume/profile service
- Future human expert marketplace
```
## 3. Workflows should be backend-owned products
The frontend should not hardcode workflows.
The backend should expose a workflow catalog like:
```ts
WorkflowDefinition {
id: "interview-to-offer"
title: "Interview-to-Offer Accelerator"
promise: "Prepare me for this specific interview and help me convert it into an offer."
segment: ["job-seekers", "students", "freshers"]
difficulty: "urgent"
estimatedDuration: "3-7 days"
priceTier: "premium"
visualTheme: {
icon: "target"
color: "violet"
mascot: "Vera"
mapStyle: "mission"
}
modules: [...]
outputs: [...]
qScoreDimensions: [...]
}
```
Then the frontend renders cards from the backend.
This gives us:
- launch control,
- pricing control,
- A/B testing,
- workflow versioning,
- different catalog by geography/user type,
- no fake frontend workflows,
- no mismatch between UI and backend reality.
## 4. Workflows are not services
This is important.
A workflow is a **business outcome**.
A service is a **capability**.
Example:
### Interview-to-Offer Accelerator
Uses:
- Q Score baseline
- Resume/profile analysis
- Interview service
- Roleplay service
- Matchmaking/context
- OpenCode artifact generation
- Gitea memory
- possibly human coach later
### Career Transition Accelerator
Uses:
- Q Score
- Resume service
- Social branding
- Matchmaking
- Roleplay
- Interview
- OpenCode
### Promotion Readiness System
Uses:
- Q Score
- Roleplay
- Resume/profile
- Social branding
- leadership evidence packet
- manager conversation simulation
So the system should have reusable backend capabilities:
```txt
Capability: analyze_resume
Capability: rewrite_linkedin
Capability: compute_qscore
Capability: run_mock_interview
Capability: run_roleplay
Capability: find_opportunities
Capability: generate_negotiation_script
Capability: create_promotion_packet
Capability: create_content_plan
Capability: update_user_memory
Capability: commit_artifact_to_git
```
Workflows compose these capabilities.
That gives us scale.
## 5. The backend should have a workflow registry
The first real backend structure should be something like:
```txt
growqr-backend/src/workflows/
registry.ts
types.ts
definitions/
interview-to-offer.ts
career-transition.ts
salary-negotiation.ts
promotion-readiness.ts
personal-brand-engine.ts
first-job-launchpad.ts
```
Each workflow definition should include:
- product metadata,
- user promise,
- visual metadata,
- required inputs,
- steps/modules,
- agent assignments,
- service dependencies,
- output artifacts,
- approval gates,
- score dimensions affected,
- billing SKU,
- version.
This becomes the source of truth for both backend and frontend.
## 6. Runtime model
A user starts a workflow:
```txt
POST /api/workflows/interview-to-offer/runs
```
Backend creates:
```txt
WorkflowRun {
id
userId
workflowId
workflowVersion
status
currentStep
modules
artifacts
timeline
qScoreBefore
qScoreAfter
}
```
Then Rivet handles durable execution.
Recommended model:
```txt
UserActor
- owns user-level state
- owns active stack/container/repo references
- routes messages
- knows current active workflows
WorkflowRunActor / Rivet Workflow
- owns one workflow run
- executes steps durably
- retries failed service calls
- waits for user approvals
- writes artifacts
- updates Q Score
- emits events to frontend
```
This prevents one user actor from becoming a giant monolith.
## 7. OpenCodes role
OpenCode should be treated as a **per-user agentic execution environment**, not as the entire backend.
It is good for:
- generating career artifacts,
- reading/writing markdown memory,
- running prompt-based agents,
- editing repo files,
- maintaining long-lived user workspace,
- producing structured outputs,
- committing artifacts to Git.
It should not be the only source of truth for:
- billing,
- workflow status,
- auth,
- permissions,
- global Q Score,
- matching index,
- public catalog,
- analytics.
Those belong in backend/Postgres/domain services.
OpenCode should be called by the workflow engine as a worker.
## 8. Gitea/Git memory role
Gitea is very valuable here.
Each user gets a repo like:
```txt
/users/{userId}/career-memory.git
```
Inside:
```txt
profile/
identity.md
goals.md
preferences.md
artifacts/
resumes/
linkedin/
interview/
negotiation/
promotion/
brand/
workflows/
interview-to-offer/
run-001/
plan.md
likely-questions.md
story-bank.md
readiness-report.md
qscore/
snapshots/
dimensions.md
conversations/
chat-summaries.md
```
The repo becomes the users career memory.
Backend/Postgres stores transactional state.
Gitea stores durable, inspectable, versioned career artifacts.
This is powerful because every workflow improves the users future workflows.
## 9. Q Score should be a platform layer
Q Score is not just another workflow.
It should be the scoring layer across everything.
Every workflow should:
1. read current Q Score,
2. identify weak dimensions,
3. improve some dimensions,
4. produce evidence/artifacts,
5. update score,
6. show before/after progress.
For the target audience, this should be visual and game-like:
```txt
Interview Readiness 62 → 78
Resume Strength 55 → 81
Market Match 49 → 67
Communication 58 → 72
Confidence 44 → 69
```
The user should feel:
> “My career power is increasing.”
That is much more engaging than showing plain reports.
## 10. Matching should consume Q Score + identity + workflow outputs
The matchmaking service should not just match from resume text.
It should use:
- Q Score dimensions,
- user goals,
- skills,
- constraints,
- location/remote preference,
- salary target,
- interview readiness,
- brand strength,
- past workflow outputs,
- user feedback,
- employer/job signals.
Then matching becomes smarter after every workflow.
Example:
A user finishes Interview-to-Offer.
Their communication score improves.
Their target role is clearer.
Their resume is stronger.
Their job matches should become better.
This creates compounding value.
## 11. Frontend should feel like missions, not forms
For Tier-2/Tier-3, India, students, freshers, and early professionals, the UX should be visual, playful, and low-reading.
Think:
```txt
Choose your mission
🎯 Convert my interview
🚀 Get my first job
🔁 Switch my career
💰 Negotiate my offer
🧠 Become promotion-ready
📣 Build my personal brand
```
Each workflow should look like a journey map:
```txt
Start → Diagnose → Build → Practice → Improve Score → Get Matched → Final Pack
```
Use:
- agent avatars,
- progress bars,
- badges,
- score cards,
- short text,
- voice/video later,
- “daily quests,”
- artifact cards,
- before/after score animations,
- celebratory milestones.
The user should not feel like they are filling enterprise forms.
## 12. Backend-first launch plan
I would structure launch like this:
### Phase 1: Backend workflow foundation
Build:
- workflow registry,
- generic workflow routes,
- workflow run model,
- module execution model,
- artifact model,
- Q Score update hooks,
- OpenCode execution adapter,
- Gitea artifact commit layer.
Do not overbuild frontend yet.
### Phase 2: First sellable workflows
Launch 3-5 strong workflows:
1. Interview-to-Offer Accelerator
2. First Job / Placement Launchpad
3. Career Transition Accelerator
4. Salary / Offer Negotiation War Room
5. Personal Brand & Opportunity Engine
These share many primitives, so implementation reuse is high.
### Phase 3: Gamified frontend
Build:
- workflow marketplace,
- mission detail pages,
- active workflow map,
- Q Score dashboard,
- artifact gallery,
- agent squad chat,
- progress timeline.
### Phase 4: Human expert layer
Add:
- coach escalation,
- mock interviewers,
- resume reviewers,
- negotiation coaches,
- placement mentors.
### Phase 5: B2B/B2B2C
Expand to:
- institutes,
- cohorts,
- placement dashboards,
- recruiter access,
- startup hiring,
- enterprise internal mobility.
## 13. The clean mental model
The product should be understood like this:
```txt
Workflow = what the user buys.
Agent Squad = how the user experiences help.
Services = specialized engines that perform parts of the work.
OpenCode = user-specific agent workspace and artifact builder.
Gitea = version-controlled career memory.
Q Score = career readiness/trust measurement layer.
Matchmaking = opportunity routing layer.
Rivet = durable orchestration/lifecycle layer.
Backend = product/control plane.
Frontend = playful mission UI.
```
## 14. What we should avoid
We should avoid:
- frontend-owned fake workflows,
- one hardcoded `job-application` flow,
- treating each service as a product page,
- making OpenCode responsible for business state,
- exposing container/password details to frontend,
- long text-heavy UX,
- workflows that only generate documents but do not improve score/matching/memory,
- losing artifacts outside Git memory,
- manual-only execution without durable workflow state.
## 15. My high-level recommendation
Architect GrowQR as a **workflow commerce platform for career outcomes**.
Backend owns the catalog and execution.
Rivet owns durability.
OpenCode owns per-user agentic artifact work.
Gitea owns long-term career memory.
Q Score owns readiness measurement.
Matching owns opportunity movement.
Frontend makes the whole thing feel like a fun, visual career game.
That gives us a coherent platform rather than a collection of disconnected tools.

View File

@@ -0,0 +1,717 @@
# GrowQR Curator — 30-Day Plan Examples by ICP
Date: 2026-06-15
Purpose: Concrete, copy-pasteable 30-day curator plans with full service integration, chat flows, and generated task shapes for each ICP.
---
## ICP: Student / Recent Grad
**Onboarding signal**: `individual + student/recent grad + 0-2 years + before graduation/within 6 months + role/skills`
**Plan theme**: "First Role Readiness Sprint"
**Goal by Day 30**: Have a credible resume, practiced 5+ interviews, active social presence, and a target role with matched opportunities.
---
### Week 1: Baseline + First Proof
| Day | Measurement | Proof | Practice |
|-----|-------------|-------|----------|
| 1 | **Q Score baseline** — review score, pick weakest driver | **Resume upload** — import LinkedIn, mark missing proof | **Pathways review** — pick target role family |
| 2 | **Q Score check** — log confidence | **Project → proof** — pick 1 project, draft 2 bullets | **Interview preview** — behavioral, 5 min, easy |
| 3 | **Q Score gap log** — tag skill gaps | **Resume gap scan** — compare to role requirements | **"Tell me about yourself"** — interview preview |
| 4 | **Q Score proof ledger** — add project tags | **Proof bank v1** — list 3 projects with metrics | **Recruiter intro roleplay** — 5 min preview |
| 5 | **Q Score confidence pulse** — rate 1-10 | **LinkedIn headline** — agent drafts, user edits | **Interview warm-up** — easy, 5 min, complete |
| 6 | **Q Score driver review** — choose next focus | **Resume bullet rewrite** — add action verbs, outcomes | **HR screen roleplay** — common questions |
| 7 | **Week review** — compare day 1 vs 7 | **STAR story #1** — challenge → action → result | **Apply to 2 roles** — matchmaking shortlist |
### Week 2: Fix Gaps + Build Presence
| Day | Measurement | Proof | Practice |
|-----|-------------|-------|----------|
| 8 | **Q Score skill gap** — pick missing skill | **Resume education section** — add relevant coursework | **Role-related interview** — medium, 10 min |
| 9 | **Q Score proof update** — add new bullets | **LinkedIn About** — agent drafts, 3 lines + proof | **Project explanation** — interview deep dive |
| 10 | **Q Score movement check** — any driver up? | **Resume keyword pass** — match JD language | **Mock interview medium** — complete + feedback |
| 11 | **Q Score communication** — log clarity | **Portfolio/GitHub** — README summary + outcome | **Weakness answer** — draft + practice |
| 12 | **Q Score application quality** — audit last 5 | **Tailored resume** — 1 JD mapped, 3 bullets | **Recruiter callback roleplay** — intro + comp + next step |
| 13 | **Q Score interview feedback** — pattern check | **STAR story #2** — teamwork example | **Mock interview replay** — weakest area |
| 14 | **Week 2 review** — callbacks? confidence? | **Credibility post** — agent drafts, project insight | **Behavioral round** — complete + feedback |
### Week 3: Repetition + Market Action
| Day | Measurement | Proof | Practice |
|-----|-------------|-------|----------|
| 15 | **Q Score interview bank** — 5 stories tagged | **Resume summary** — agent drafts, role-targeted | **Salary expectation roleplay** — define range, practice |
| 16 | **Q Score skill drill** — 3 questions answered | **Resume final pass** — grammar, keywords, export | **Hard question practice** — 3 questions, preview |
| 17 | **Q Score readiness check** — lowest service signal | **Portfolio polish** — add demo link, screenshot | **Project deep dive** — explain tradeoffs, preview |
| 18 | **Q Score application audit** — drop-off analysis | **Profile proof link** — featured section update | **Rejection recovery roleplay** — ask for feedback |
| 19 | **Q Score proof bank** — tag stories to questions | **Case study mini-deck** — before/after/result | **Full round mock** — medium, 10 min, feedback |
| 20 | **Q Score confidence repair** — anxiety → warm-up | **Resume export** — PDF, role-named, saved | **Fresher pitch** — 60 sec, practice, save |
| 21 | **Week 3 review** — conversion bottleneck | **Top-company resume** — tailored version | **Target company prep** — research + questions |
### Week 4: Conversion + Next Sprint
| Day | Measurement | Proof | Practice |
|-----|-------------|-------|----------|
| 22 | **Q Score behavioral refinement** — weakest STAR | **LinkedIn activity boost** — agent suggests 3 comments | **Recruiter screen replay** — comp + location |
| 23 | **Q Score hard mode** — stress test | **Resume final export** — 2 versions | **Mock interview hard** — complete + review |
| 24 | **Q Score improvement log** — day 1 vs 24 | **Case study polish** — add metric, publish | **Rejection recovery** — practice, save script |
| 25 | **Q Score interview for top role** — best role | **Proof bank update** — new stories, metrics | **Referral ask** — roleplay, send message |
| 26 | **Q Score application sprint** — 3 high-fit roles | **Profile final polish** — agent audits, suggests | **Confidence pitch** — roleplay, save script |
| 27 | **Q Score replay** — weakest area, compare | **Resume versions** — 2 role exports | **Questions to ask** — 5 smart, tailored |
| 28 | **Q Score readiness review** — baseline vs current | **Progress post** — agent drafts, learning highlight | **Mock interview final** — complete + feedback |
| 29 | **Q Score offer readiness** — negotiation check | **Resume export** — final PDF, role-named | **Offer call roleplay** — salary + closing |
| 30 | **Q Score 30-day outcome** — record wins, gaps | **Next sprint plan** — interview, callbacks, skills | **Claim streak** — reward, next cadence |
### Example curator task shapes
**Day 2 — Interview preview**
```json
{
"title": "Prepare your first mock interview",
"subtitle": "Behavioral round · 5 minutes · Easy pressure",
"serviceId": "interview-service",
"cta": "Open interview preview",
"contextNarrative": "Student targeting first role, needs confidence before real interviews.",
"subtasks": ["Confirm role", "Select behavioral", "Generate preview", "Complete practice"],
"signals": ["interview.confidence", "communication_clarity"],
"previewParams": { "type": "behavioral", "difficulty": "easy", "duration": 5, "source": "curator-v1" }
}
```
**Day 5 — Agent-Social Branding**
```json
{
"title": "Draft your first credibility post",
"subtitle": "Agent suggests topic, drafts copy, optimizes timing",
"serviceId": "agent-social-branding",
"cta": "Draft post with agent",
"contextNarrative": "Student has project proof but no visibility. Agent builds inbound.",
"subtasks": ["Agent analyzes work", "Drafts post with hook", "User edits", "Agent schedules"],
"signals": ["visibility", "profile_strength", "public_proof"]
}
```
**Day 7 — Job Matchmaking**
```json
{
"title": "Match with 2 aligned roles",
"subtitle": "Resume ready. Find high-fit opportunities.",
"serviceId": "job-matchmaking",
"cta": "See matched roles",
"contextNarrative": "Student has improved resume and interview readiness. Time for active pipeline.",
"subtasks": ["Analyze resume vs roles", "Score top 5", "Surface matches", "Track applications"],
"signals": ["opportunity_awareness", "pipeline_health", "proactive_search"]
}
```
### Chat flow example — Day 2 Interview
**User clicks**: "Prepare your first mock interview"
**Curator**: This is your practice step for today. What role or interview round should I prepare the preview for?
**User**: Product manager
**Curator**: Got it. I prepared a mock interview preview for Product Manager behavioral practice. Behavioral · 5 minutes · Easy pressure. Open the preview to start or adjust the setup.
**[CTA card appears]**
- Eyebrow: INTERVIEW PREVIEW
- Title: Your mock interview is ready
- Subtitle: Behavioral · 5 min · Easy · Product Manager
- Button: Open interview preview → `/agents/interview/preview?role=Product+Manager&type=behavioral&difficulty=easy&duration=5&source=curator-v1`
---
## ICP: Intern
**Onboarding signal**: `individual + student/recent grad or 0-2 years + employed/internship + role/pay/grow`
**Plan theme**: "Intern-to-Offer Sprint"
**Goal by Day 30**: Convert internship into full-time offer or strong external backup.
---
### Week 1: Impact + Communication
| Day | Measurement | Proof | Practice |
|-----|-------------|-------|----------|
| 1 | **Q Score baseline** — communication/proof drivers | **Capture current project** — describe, stakeholder, expected result | **Define internship outcome** — return offer / feedback / impact |
| 2 | **Q Score pulse** — log confidence | **Turn internship work into proof** — action/result bullet | **Manager check-in roleplay** — define ask, practice |
| 3 | **Q Score metrics** — list project KPIs | **Update resume internship section** — company, team, project | **Feedback request roleplay** — practice ask |
| 4 | **Q Score return-offer readiness** — identify requirements | **Weekly update** — agent drafts, shipped work, learnings | **Return-offer interview preview** — behavioral, 5 min |
| 5 | **Q Score mock feedback** — warm-up round | **Impact log start** — weekly wins, metrics | **Manager update roleplay** — concise status |
| 6 | **Q Score scope check** — desired project | **Improve internship bullet** — agent suggests action verbs | **Ask for better scope roleplay** — practice |
| 7 | **Week 1 review** — project progress, blockers | **Mentor conversation prep** — roleplay, save ask | **Publish learning proof** — agent drafts, anonymized |
### Week 2: Conversion + Visibility
| Day | Measurement | Proof | Practice |
|-----|-------------|-------|----------|
| 8 | **Q Score return-offer check** — compare proof to requirements | **Manager check-in email** — agent drafts, progress + ask | **Project deep dive interview** — open preview, practice |
| 9 | **Q Score blocker conversation** — conflict roleplay | **Document project decisions** — list, rationale, proof bank | **Resume proof pass** — collaboration, tools, skills |
| 10 | **Q Score mock return-offer** — complete + feedback | **Peer feedback request** — draft, send | **Q Score update** — add internship proof |
| 11 | **Q Score final project narrative** — before/action/after | **Profile headline** — agent adds internship role, target | **Full-time conversion roleplay** — timing, ask, practice |
| 12 | **Q Score technical questions** — 5 likely, practice | **Manager visibility** — agent drafts update, send | **Portfolio artifact** — anonymize, write summary |
| 13 | **Q Score feedback synthesis** — pattern, improvement | **Resume internship v1** — tighten bullets, metrics, export | **Receiving criticism roleplay** — practice response |
| 14 | **Week 2 review** — impact log, feedback, conversion action | **Thank-you note** — agent drafts, mentor, send | **Interview replay** — weakest topic |
### Week 3: Offer Path + Backup
| Day | Measurement | Proof | Practice |
|-----|-------------|-------|----------|
| 15 | **Q Score offer path map** — decision maker, timeline, proof | **Roleplay offer conversation** — define ask, practice | **Strengthen project proof** — metric, stakeholder quote |
| 16 | **Q Score mock medium** — complete + review | **Demo/update deck** — 3 slides, result | **LinkedIn update** — agent drafts internship lesson |
| 17 | **Q Score explicit feedback** — 3 questions, roleplay | **Prioritization roleplay** — conflict, tradeoff | **Q Score signal review** — lowest driver, route task |
| 18 | **Q Score return-offer preview** — role, behavioral, practice | **Manager 1-on-1 prep** — agenda, wins, asks | **Resume role-fit tailoring** — post-internship role |
| 19 | **Q Score project storytelling** — 90-sec story, interview | **Internal networking** — team member intro, schedule | **Impact log refresh** — week wins, blockers solved |
| 20 | **Q Score conversion close** — direct ask, hesitation | **Mock feedback loop** — compare attempts, schedule next | **Profile polish** — agent updates headline, proof |
| 21 | **Week 3 review** — offer odds, missing proof, final week | **Final presentation** — outline impact, metric, rehearse | **Q Score progress** — baseline vs current |
### Week 4: Final Push + Close
| Day | Measurement | Proof | Practice |
|-----|-------------|-------|----------|
| 22 | **Q Score presentation Q&A** — likely questions, interview | **Manager decision roleplay** — outcome, ask, save | **Resume final bullets** — refine 3, export role version |
| 23 | **Q Score stakeholder thank-you** — agent drafts notes | **Mock hard round** — complete + review | **External backup** — 5 roles, tailor, shortlist |
| 24 | **Q Score promotion/return script** — write, practice | **Portfolio case study** — anonymize, challenge/action/result | **LinkedIn final** — agent drafts, review, publish |
| 25 | **Q Score offer conversation** — roleplay, comp, closing | **Interview final polish** — top 3 answers, feedback | **Q Score readiness summary** — signals, final note |
| 26 | **Q Score recommendation** — person, draft, roleplay | **Application backup** — 3 roles, record, follow up | **Manager final update** — agent summarizes impact, interest |
| 27 | **Q Score decision rehearsal** — comp, scope, script | **Resume export** — final grammar, PDF, version | **Proof bank** — tag stories, metrics |
| 28 | **Q Score final review** — goals, outcomes, next move | **Mock replay** — weakness, compare, save | **Relationship plan** — contacts, follow-ups |
| 29 | **Q Score offer/next role** — scenario, practice | **Q Score closeout** — day 1 vs 29, evidence, next sprint | **Milestone update** — agent drafts, publish |
| 30 | **Q Score outcome** — offer/status, lessons, next plan | **Next sprint** — return offer, external, skill, leadership | **Claim streak** — reward, cadence |
### Chat flow example — Day 4 Return-offer Interview
**Curator**: Which return-offer role or team should this interview prepare you for?
**User**: Full-time PM on the growth team
**Curator**: Got it. I prepared a return-offer interview preview for Growth PM, behavioral round. 5 minutes. You can practice with your internship project as proof. Open the preview to start.
**[CTA card]**
- Eyebrow: INTERVIEW PREVIEW
- Title: Return-offer interview preview
- Subtitle: Growth PM · Behavioral · 5 min · Medium
- Details: Role: Growth PM | Round: Behavioral | Difficulty: Medium
- Button: Open preview → `/agents/interview/preview?role=Growth+PM&type=behavioral&difficulty=medium&duration=5&source=curator-v1`
---
## ICP: Fresher / Early Professional (< 5 years)
**Onboarding signal**: `individual + 0-2 or 2-5 years + hunting/between/employed + callbacks/interviews/profile/pay/switch`
**Plan theme**: "Callback-to-Offer Sprint"
**Goal by Day 30**: Resume converts to callbacks, 3+ interviews practiced, 5+ applications tracked, salary confidence built.
---
### Week 1: Diagnose + Fix
| Day | Measurement | Proof | Practice |
|-----|-------------|-------|----------|
| 1 | **Q Score baseline** — weakest driver | **Resume upload** — import, mark missing | **Target role** — pick role, industry, save |
| 2 | **Q Score resume fit** — compare to JD, top 3 fixes | **Interview warm-up** — easy, 5 min | **Headline rewrite** — agent drafts, target role |
| 3 | **Q Score callback diagnosis** — mismatch analysis | **STAR story #1** — achievement, structure | **Recruiter screen roleplay** — practice |
| 4 | **Q Score resume bullets** — metrics pass | **"Why this role"** — define, interview preview | **Application shortlist** — 5 roles, rank, save 3 |
| 5 | **Q Score mock medium** — complete + feedback | **LinkedIn About** — agent drafts, proof | **Q Score check-in** — movement, next driver |
| 6 | **Q Score tailored resume** — 1 JD, keywords | **Salary expectation roleplay** — range, practice | **Recruiter outreach** — agent drafts, send 2 |
| 7 | **Week 1 review** — applications, mock feedback | **Apply to 3 roles** — matchmaking, track | **Credibility post** — agent drafts, work lesson |
### Week 2: Practice + Presence
| Day | Measurement | Proof | Practice |
|-----|-------------|-------|----------|
| 8 | **Q Score interview weakness** — drill, preview | **Proof bank** — wins, metrics, questions | **Profile visibility** — agent suggests 3 comments |
| 9 | **Q Score role transition** — current vs target, gap | **Resume gap fix** — missing skill proof | **Networking call roleplay** — contact, ask |
| 10 | **Q Score mock role-related** — complete + review | **Follow-up sprint** — 3 pending, send | **Q Score proof update** — resume changes, driver |
| 11 | **Q Score STAR #2** — conflict/teamwork | **Weakness answer** — draft, interview, practice | **Opportunity refresh** — 5 roles, rank, save |
| 12 | **Q Score recruiter call** — intro, comp, next step | **Resume final role version** — summary, bullets, export | **Profile proof link** — featured section update |
| 13 | **Q Score feedback loop** — pattern, practice again | **Application audit** — 5 scored, remove bad-fit | **Referral ask** — agent drafts, send |
| 14 | **Week 2 review** — callbacks, confidence, conversion | **Behavioral round** — complete + feedback | **Proof post** — agent drafts, result |
### Week 3: Conversion + Negotiation
| Day | Measurement | Proof | Practice |
|-----|-------------|-------|----------|
| 15 | **Q Score conversion plan** — weak round, cadence | **Resume summary** — agent drafts, role-targeted | **Offer/salary roleplay** — scenario, range, practice |
| 16 | **Q Score hard questions** — 3 questions, preview | **Recruiter pipeline** — active leads, follow-up | **Q Score review** — lowest driver, route next |
| 17 | **Q Score project deep dive** — decisions, preview | **Networking follow-up** — 3 contacts, response | **Profile credibility** — agent audits, saves |
| 18 | **Q Score application sprint** — 3 roles, record | **Rejection recovery** — feedback ask, script | **STAR #3** — leadership, structure |
| 19 | **Q Score full round** — complete + review | **Resume keyword pass** — JD terms, export | **Personal brand post** — agent drafts, insight |
| 20 | **Q Score answer polish** — top 3, shorten, practice | **Hiring manager roleplay** — scenario, preview | **Q Score progress** — baseline vs current, final sprint |
| 21 | **Week 3 review** — interviews, callbacks, blocker | **Target company prep** — research, questions | **Follow-up sprint** — pending, send 3 |
### Week 4: Final Push + Close
| Day | Measurement | Proof | Practice |
|-----|-------------|-------|----------|
| 22 | **Q Score target company** — role, context, preview | **Referral roleplay** — contact, ask, send | **Resume final polish** — grammar, export |
| 23 | **Q Score salary negotiation** — range, roleplay, script | **Portfolio case** — project, summary, save | **Q Score readiness** — review, gap, act |
| 24 | **Q Score hard mode** — complete + review | **LinkedIn visibility** — agent updates, posts, messages | **Conversion audit** — stages, drop-off, fix |
| 25 | **Q Score offer call** — scenario, practice, save | **Interview replay** — weakest, preview, compare | **Proof bank final** — tag, metrics, save |
| 26 | **Q Score final sprint** — 3 high-fit, record | **Manager/recruiter drill** — scenario, roleplay | **Profile proof** — agent drafts, publish |
| 27 | **Q Score questions to ask** — 5 smart, tailored | **Resume versions** — 2 roles, export | **Q Score final push** — driver, act |
| 28 | **Q Score readiness review** — baseline vs artifacts | **Mock final** — complete + feedback | **Networking plan** — weekly, save |
| 29 | **Q Score negotiation replay** — practice, script | **Pipeline review** — active, actions, deadlines | **Profile final** — agent audits, saves |
| 30 | **Q Score 30-day outcome** — callbacks, interviews, wins | **Next plan** — conversion, negotiation, transition | **Claim streak** — reward, cadence |
### Chat flow example — Day 6 Salary Roleplay
**Curator**: What salary conversation do you need to prepare for: recruiter screen, offer call, or manager discussion?
**User**: Recruiter screen
**Curator**: Got it. What range are you expecting? Even a rough number helps me prepare the right scenario.
**User**: 8-12 LPA
**Curator**: Got it. I prepared a roleplay preview for a recruiter salary screen. Recruiter asks about expectations, you practice saying 8-12 LPA with confidence. Open the preview to practice.
**[CTA card]**
- Eyebrow: ROLEPLAY PREVIEW
- Title: Recruiter salary screen
- Subtitle: Practice saying your range with confidence
- Details: Counterpart: Recruiter | Scenario: First screen | Range: 8-12 LPA
- Button: Open preview → `/agents/roleplay/preview?scenario=salary_screen&counterpart=recruiter&range=8-12+LPA&source=curator-v1`
---
## ICP: Experienced Professional (> 5 years)
**Onboarding signal**: `individual + 5-10 or 10+ years + employed/between/leading + leadership/pay/scope/authority`
**Plan theme**: "Leadership Readiness Sprint"
**Goal by Day 30**: Leadership proof packaged, senior interview confidence, promotion/scope negotiation practiced, authority presence built, 3+ senior roles matched.
---
### Week 1: Leadership Proof + Direction
| Day | Measurement | Proof | Practice |
|-----|-------------|-------|----------|
| 1 | **Leadership Q Score baseline** — leadership drivers | **Import proof** — LinkedIn, site, mark missing | **Leadership target** — pick role, scope, save |
| 2 | **Leadership gap map** — current vs target | **Leadership impact bullet** — project, team, outcome | **Senior stakeholder interview** — leadership round, preview |
| 3 | **Leadership positioning** — agent drafts headline | **Leadership resume audit** — execution → scope | **Promotion roleplay** — title, scope, practice |
| 4 | **Leadership proof bank** — team outcomes, metrics | **Senior team interview** — preview, practice | **Match senior roles** — score, save |
| 5 | **Leadership behavioral mock** — complete + feedback | **LinkedIn positioning** — agent updates, proof | **Q Score check** — movement, next driver |
| 6 | **Leadership compensation** — package, roleplay | **Leadership case study** — transformation, before/after | **Authority post** — agent drafts, insight |
| 7 | **Week 1 review** — score, choose week 2 | **Apply to senior roles** — 3 roles, tailor, track | **Board/executive interview** — preview, save |
### Week 2: Authority + Senior Practice
| Day | Measurement | Proof | Practice |
|-----|-------------|-------|----------|
| 8 | **Leadership STAR** — team challenge, structure | **Difficult stakeholder roleplay** — scenario, practice | **Profile credibility** — agent audits, saves |
| 9 | **Leadership bullets final** — scope, metrics, export | **Strategy round interview** — preview, practice | **Executive recruiter intro** — agent drafts, send |
| 10 | **Leadership full mock** — complete + review | **Q Score update** — add proof, driver | **Networking follow-up** — 3 contacts |
| 11 | **Leadership "why this company"** — research, draft | **Compensation roleplay** — package, practice | **Authority post #2** — agent drafts |
| 12 | **Leadership case study** — transformation, save | **Leadership weakness** — gap, preview, practice | **Match executive roles** — C-suite/VP, score |
| 13 | **Board/executive mock** — complete + review | **Profile final** — agent audits, suggests | **Q Score final gap** — choose, act |
| 14 | **Week 2 review** — interviews, conversion | **Offer negotiation roleplay** — package, practice | **Leadership post** — agent drafts |
### Week 3: Conversion + Executive Presence
| Day | Measurement | Proof | Practice |
|-----|-------------|-------|----------|
| 15 | **Leadership conversion plan** — weak round, practice | **Managing up roleplay** — scenario, save | **Resume versions** — 2 roles, export |
| 16 | **Hard leadership questions** — 3 questions, preview | **Recruiter pipeline** — leads, follow-up | **Q Score review** — driver, route |
| 17 | **Leadership deep dive** — project, tradeoffs, preview | **Executive networking** — follow up, record | **Profile final** — agent audits, saves |
| 18 | **Application sprint** — 3 senior roles, record | **Rejection to next role** — roleplay, save | **STAR transformation** — structure, save |
| 19 | **Executive full mock** — complete + review | **Resume keyword** — leadership terms, export | **Thought leadership** — agent drafts |
| 20 | **Answer polish** — top 3, shorten, practice | **Hiring manager roleplay** — preview, practice | **Q Score progress** — compare, final sprint |
| 21 | **Week 3 review** — blocker, final push | **Target company** — research, questions | **Follow-up** — pending, send |
### Week 4: Close + Next Level
| Day | Measurement | Proof | Practice |
|-----|-------------|-------|----------|
| 22 | **Target company mock** — role, context, preview | **Referral** — contact, practice, send | **Resume final** — grammar, export |
| 23 | **Negotiation prep** — package, roleplay, script | **Portfolio case** — write, save | **Q Score readiness** — gap, act |
| 24 | **Hard mode** — complete + review | **LinkedIn visibility** — agent updates, posts | **Conversion audit** — stages, fix |
| 25 | **Offer call** — scenario, practice, save | **Interview replay** — weakest, compare | **Proof bank final** — tag, save |
| 26 | **Final sprint** — 3 senior, record | **Communication drill** — roleplay, save | **Profile proof** — agent drafts |
| 27 | **Questions to ask** — 5 smart, tailored | **Resume versions** — 2 roles, export | **Q Score final push** — driver, act |
| 28 | **Readiness review** — baseline vs artifacts | **Mock final** — complete + feedback | **Networking plan** — schedule |
| 29 | **Negotiation replay** — practice, script | **Pipeline review** — active, deadlines | **Profile final** — agent audits |
| 30 | **30-day outcome** — score, wins, next | **Next plan** — leadership, compensation, transition | **Claim streak** — reward, cadence |
### Chat flow example — Day 3 Promotion Roleplay
**Curator**: What are you asking for: title change, salary increase, larger scope, or leadership opportunity?
**User**: Title change to Engineering Manager + 20% bump
**Curator**: Got it. I prepared a roleplay preview for a promotion conversation with your manager. Scope: EM title + 20% increase. You will practice the ask, handle hesitation, and close with a next step. Open the preview to practice.
**[CTA card]**
- Eyebrow: ROLEPLAY PREVIEW
- Title: Promotion conversation
- Subtitle: Engineering Manager title + 20% increase
- Details: Counterpart: Manager | Ask: Title + comp | Outcome: Agreement or next step
- Button: Open preview → `/agents/roleplay/preview?scenario=promotion&counterpart=manager&ask=EM+title+20%25&source=curator-v1`
---
## ICP: Freelancer / Gig Worker
**Onboarding signal**: `gig + starting/fewclients/sidehustle + clients/pricing/standout/trust/income + firstclient/doubleincome/fulltime/1lakh`
**Plan theme**: "Client Pipeline Sprint"
**Goal by Day 30**: Clear offer, 10+ leads contacted, 2+ discovery calls practiced, pricing confidence, 2+ case studies, inbound presence started.
---
### Week 1: Niche + Offer + First Outreach
| Day | Measurement | Proof | Practice |
|-----|-------------|-------|----------|
| 1 | **Q Score baseline** — credibility/trust drivers | **Import portfolio** — LinkedIn, GitHub, mark gaps | **Define niche** — target client, pain, save |
| 2 | **Package offer** — problem, deliverable, line | **Discovery call preview** — client scenario, practice | **Headline** — agent drafts, client type, outcome |
| 3 | **Build case study #1** — before/action/after | **Pricing roleplay** — current/target rate, practice | **Inbound post** — agent picks pain, drafts |
| 4 | **Pipeline map** — lead sources, top 2 | **Offer page polish** — proof, CTA | **Objection handling** — pick, practice |
| 5 | **Q Score trust check** — credibility gaps | **Outreach sprint** — 5 messages, send | **Portfolio proof** — metric, testimonial |
| 6 | **Discovery script** — 5 questions, roleplay | **Pricing page** — tiers, outcomes | **Credibility post** — agent drafts, publish |
| 7 | **Week 1 review** — leads, replies, week 2 focus | **Follow-up roleplay** — polite, send 3 | **Profile update** — agent audits, saves |
### Week 2: Pipeline + Conversion
| Day | Measurement | Proof | Practice |
|-----|-------------|-------|----------|
| 8 | **Lead list** — 20 prospects, score top 10 | **First client call** — scenario, close, practice | **Case study polish** — visuals, outcome, publish |
| 9 | **Offer specificity** — narrow audience, outcome | **Pricing objection drill** — choose, practice | **Cold DM** — agent drafts, personalize 5, send |
| 10 | **Q Score credibility** — add case, movement | **Discovery replay** — practice, save feedback | **Inbound content** — agent drafts, pain, CTA |
| 11 | **Referral ask** — past client, draft, roleplay | **Portfolio audit** — weak section, rewrite | **Pipeline follow-up** — 5 leads, status |
| 12 | **Proposal structure** — problem, solution, timeline, price | **Proposal call** — client, preview, practice | **Proof post** — agent drafts, case insight |
| 13 | **Rate increase plan** — current, target, proof | **Pricing hard mode** — discount, scope, practice | **Lead source review** — channels, double down |
| 14 | **Week 2 review** — leads, calls, bottleneck | **Profile CTA** — agent writes clear, booking | **Discovery practice** — preview, save |
### Week 3: Close + Premium Positioning
| Day | Measurement | Proof | Practice |
|-----|-------------|-------|----------|
| 15 | **Conversion plan** — active leads, next action | **Scope creep roleplay** — boundary, script | **Case study #2** — choose, draft, save |
| 16 | **Proposal follow-up** — draft, roleplay, send | **Q Score trust** — proof, social, improvement | **Authority post** — agent drafts, lesson |
| 17 | **Package refinement** — starter, premium | **Premium offer roleplay** — quote, pushback, save | **Outreach sprint** — 5 targeted, send |
| 18 | **Testimonial request** — client, draft, send | **Client call replay** — discovery, proposal, save | **Portfolio update** — testimonial, result |
| 19 | **Inbound post #2** — agent picks pain, drafts | **Difficult client** — late payment, scope, practice | **Pipeline health** — leads, calls, proposals |
| 20 | **Pricing confidence** — day 3 vs 20, script | **Proposal template** — sections, pricing, save | **Q Score progress** — baseline, final sprint |
| 21 | **Week 3 review** — conversion bottleneck, push | **Close call** — practice, hesitation, save | **Lead refresh** — 20 new, score, save |
### Week 4: Full-time + Inbound
| Day | Measurement | Proof | Practice |
|-----|-------------|-------|----------|
| 22 | **Full-time plan** — income target, client count | **Retainer roleplay** — monthly, practice | **Profile final** — agent audits, case, CTA |
| 23 | **Outreach sprint** — 10 personalized, send | **Discovery final** — preview, practice, save | **Publish case study** — finalize, publish, share |
| 24 | **Referral engine** — ask, 10 contacts, send 3 | **Difficult negotiation** — discount, scope, practice | **Q Score credibility** — review, last improvement |
| 25 | **Proposal follow-up** — list, write, send | **Premium positioning** — rewrite, proof, save | **Authority post** — agent drafts, insight |
| 26 | **Onboarding script** — first call, roleplay | **Portfolio export** — links, CTA, save | **Pipeline actions** — every lead, next step |
| 27 | **Close practice** — preview, script | **Retainer offer** — recurring value, price, terms | **Follow-up 5** — draft, send, record |
| 28 | **Pipeline review** — leads, calls, revenue | **Case study final** — outcome, share, save | **Q Score final** — baseline, trust, next sprint |
| 29 | **Highest-value call** — active lead, practice | **Recurring income plan** — retainer target, prospects | **Progress post** — agent drafts, learning |
| 30 | **Outcome review** — leads, replies, calls, wins | **Next sprint** — first client, premium, retainer, brand | **Claim streak** — reward, cadence |
### Chat flow example — Day 3 Pricing Roleplay
**Curator**: What service are you pricing, and what rate do you want to confidently quote?
**User**: UI design, $75/hour
**Curator**: Got it. I prepared a pricing conversation roleplay. Client asks "What's your rate?" You practice saying $75/hour without apologizing. Objections: "That's expensive" and "Can you do $50?" Open the preview to practice.
**[CTA card]**
- Eyebrow: ROLEPLAY PREVIEW
- Title: Pricing conversation
- Subtitle: UI design · $75/hour
- Details: Client: Generic prospect | Service: UI design | Rate: $75/hr
- Button: Open preview → `/agents/roleplay/preview?scenario=pricing&service=ui_design&rate=75&counterpart=client&source=curator-v1`
---
## ICP: Founder / Solopreneur
**Onboarding signal**: `founder + idea/MVP/traction/pre-revenue + customers/funding/visibility/team/model + 90-day priority`
**Plan theme**: "Founder Visibility & Validation Sprint"
**Goal by Day 30**: Validated assumptions, 10+ customer conversations, founder brand active, investor pitch ready, 3+ pilot prospects, 1+ hire/collaborator identified.
---
### Week 1: Priority + Validation
| Day | Measurement | Proof | Practice |
|-----|-------------|-------|----------|
| 1 | **90-day priority** — MVP, customers, raise, hire | **Founder Q Score baseline** — credibility drivers | **Import proof** — LinkedIn, site, deck, gaps |
| 2 | **Founder one-liner** — agent drafts: audience, problem, solution | **Customer discovery preview** — segment, assumption | **Profile headline** — agent drafts, role, venture |
| 3 | **Riskiest assumption** — identify, evidence needed | **Build-in-public post** — agent picks learning, drafts | **Customer list** — ICP, 20 prospects, score top 10 |
| 4 | **Discovery script** — 5 questions, non-leading | **Customer interview roleplay** — preview, practice | **Credibility audit** — agent reviews profile, site, deck |
| 5 | **Q Score validation** — credibility, clarity | **Outreach to customers** — 5 messages, send | **One-liner revision** — agent simplifies, adds pain |
| 6 | **Investor narrative** — problem, insight, proof | **Objection handling** — customer objection, practice | **Market insight** — agent drafts, publish |
| 7 | **Week 1 review** — calls, replies, learning | **Discovery follow-up** — write, send, record | **Profile update** — agent updates headline, one-liner |
### Week 2: Customer + Investor
| Day | Measurement | Proof | Practice |
|-----|-------------|-------|----------|
| 8 | **Customer discovery round 2** — refine ICP, 5 more | **Investor intro roleplay** — stage, proof, practice | **Deck/site clarity** — problem, audience, rewrite |
| 9 | **Pricing hypothesis** — price, buyer, test | **Pricing roleplay** — preview, practice | **Founder update** — agent drafts, learning, publish |
| 10 | **Q Score credibility** — profile, deck, movement | **Customer call replay** — weak question, save | **Pipeline update** — statuses, next actions |
| 11 | **MVP scope** — features, must-have, cut one | **Cofounder alignment** — role, preview, practice | **Authority post** — agent picks contrarian, drafts |
| 12 | **First customer offer** — pilot, outcome, price | **Sales discovery roleplay** — buyer, next step, practice | **Profile proof** — agent adds traction, learning |
| 13 | **Investor intro email** — concise, proof, send | **Investor objections** — market, team, traction, practice | **Customer synthesis** — calls, pattern, save |
| 14 | **Week 2 review** — calls, learnings, conversion | **Build-in-public #2** — agent drafts, learning, metric | **Q Score check** — clarity, visibility, next action |
### Week 3: Conversion + Fundraising
| Day | Measurement | Proof | Practice |
|-----|-------------|-------|----------|
| 15 | **Conversion plan** — prospects, next ask, deadlines | **Pilot close roleplay** — offer, objection, next step | **Deck one-liner** — problem, solution, why now |
| 16 | **Hiring need** — role, outcomes, must-haves | **First hire interview** — role, preview, practice | **Profile social proof** — agent adds customers, advisors |
| 17 | **Customer sprint** — 10 messages, replies, calls | **Hard customer call** — skeptical, practice, save | **Market narrative** — agent drafts, insight, publish |
| 18 | **Fundraising readiness** — stage, proof, gaps | **Investor replay** — preview, practice, save | **Deck/site proof** — traction, quotes, add |
| 19 | **Model validation** — unit assumption, test, evidence | **Pricing/buyer roleplay** — preview, practice | **Pipeline follow-up** — 5 prospects, record |
| 20 | **Q Score progress** — baseline, strongest, weakest | **Founder pitch** — 60 sec, roleplay, save | **Build-in-public #3** — agent drafts, progress, challenge |
| 21 | **Week 3 review** — validation, pipeline, final push | **Pilot proposal** — scope, timeline, price, metric | **Closing roleplay** — customer, next step, practice |
### Week 4: Close + Scale
| Day | Measurement | Proof | Practice |
|-----|-------------|-------|----------|
| 22 | **Investor FAQ** — hard questions, draft answers | **Collaborator preview** — role, criteria, preview | **Profile polish** — agent audits headline, one-liner, proof |
| 23 | **Customer outreach** — 10, record, schedule | **Objection: no budget** — practice, save | **Authority post** — agent drafts, market lesson |
| 24 | **Traction proof** — calls, users, revenue, summarize | **Investor replay** — preview, practice, save | **Q Score final gap** — choose, complete, save |
| 25 | **Pilot close sprint** — prospects, close asks, record | **Pitch final** — 60 sec, tighten, practice | **Deck/site clarity final** — problem, solution, proof, CTA |
| 26 | **Hiring outreach** — target, message, send 5 | **Cofounder conversation** — equity, scope, values, practice | **Milestone update** — agent drafts, metric, publish |
| 27 | **Customer synthesis** — patterns, pivot/persevere | **Next-step close** — pilot, customer, investor, practice | **Credibility final** — agent audits profile, site, links |
| 28 | **Validation review** — evidence, gaps, decision | **Q Score closeout** — baseline, drivers, next | **Recap** — agent drafts progress, publish |
| 29 | **Highest-stakes conversation** — investor, customer, hire | **Pipeline actions** — every prospect, next step, deadline | **Pitch/deck export** — final file, share-ready |
| 30 | **Outcome review** — calls, customers, proof, score | **Next sprint** — MVP, customers, raise, hire, visibility | **Claim streak** — reward, cadence |
### Chat flow example — Day 2 Customer Discovery
**Curator**: Are you trying to validate customers, raise, hire, or build visibility first?
**User**: Validate customers
**Curator**: Good. Which customer segment should this discovery call simulate? Or should I suggest one based on your product?
**User**: B2B SaaS founders
**Curator**: Got it. I prepared a customer discovery roleplay preview. B2B SaaS founder segment. You practice asking non-leading questions about their workflow. The goal: validate your riskiest assumption. Open the preview to practice.
**[CTA card]**
- Eyebrow: ROLEPLAY PREVIEW
- Title: Customer discovery call
- Subtitle: B2B SaaS founders · Validate riskiest assumption
- Details: Segment: B2B SaaS founders | Goal: Validate assumption | Duration: 10 min
- Button: Open preview → `/agents/roleplay/preview?scenario=customer_discovery&segment=b2b_saas_founders&goal=validate_assumption&source=curator-v1`
---
## Prompt Templates (Copy-Paste Ready)
### Curator base system prompt
```
You are the GrowQR Curator. You own the user's 30/60-day growth plan.
Rules:
- One focused question at a time.
- No motivational paragraphs.
- No internal route names in chat text.
- Always explain business value in plain words.
- Connect every task back to the user's goal.
- Ask → Capture → Summarize → Handoff.
Services you can route to:
- Q Score: measurement, baseline, gap check
- Resume: proof packaging, bullets, audit
- Interview: confidence, preview, practice
- Roleplay: conversation rehearsal, negotiation
- Agent-Social Branding: agent-drafted posts, profile polish
- Job Matchmaking: active scoring, warm intros, pipeline
- Courses: skill gap modules, progress tracked to Q Score
- Pathways: direction, trajectory, archetype fit
Handoff rules:
- Interview: gather role + round type → preview with defaults
- Roleplay: gather scenario + counterpart → preview with defaults
- Resume: gather target role → open workspace
- Agent-Social Branding: gather topic or suggest → open branding workspace
- Job Matchmaking: gather search intent → open matchmaking dashboard
- Courses: identify skill gap → open course player
- Pathways: gather direction question → open pathways report
Default preview params:
- Interview: type=behavioral, difficulty=medium, duration=5
- Roleplay: outcome=practice, source=curator-v1
CTA copy:
- Interview: "Open interview preview"
- Roleplay: "Open roleplay preview"
- Resume: "Open resume workspace"
- Agent-Social Branding: "Draft post with agent"
- Job Matchmaking: "See matched roles"
- Courses: "Start skill module"
- Pathways: "Review pathway"
```
### First-turn prompt by service
**Interview**: "This is your practice step for today. What role or interview round should I prepare the preview for?"
**Roleplay**: "Let's rehearse the conversation before it matters. Who are you speaking with: recruiter, manager, client, investor, or customer?"
**Resume**: "Let's turn your experience into proof. What role or audience should this resume section target?"
**Agent-Social Branding**: "Let's build your visibility engine. Should I suggest a topic based on your recent work, or do you have a specific insight in mind?"
**Job Matchmaking**: "Your profile is ready. Should I find roles that match your current skills, or roles that push you toward your target direction?"
**Courses**: "I spotted a skill gap between your target role and your current proof. Which module feels most urgent: coding, analytics, communication, or strategy?"
**Pathways**: "Let's clarify your direction. Are you trying to validate a target role, explore alternatives, or plan a transition?"
### Handoff-ready prompt
**Interview**: "Got it. I prepared a mock interview preview for [ROLE] [TYPE] practice. [TYPE] · [DURATION] min · [DIFFICULTY] pressure. Open the preview to start or adjust the setup."
**Roleplay**: "Got it. I prepared a roleplay preview for a [SCENARIO] with a [COUNTERPART]. Open the preview to practice or adjust details."
**Resume**: "Saved. Open the resume workspace and we'll turn this into role-fit proof."
**Agent-Social Branding**: "The agent drafted a post about [TOPIC]. Review it in the branding workspace and approve when ready."
**Job Matchmaking**: "I found [N] roles that match your profile. See the matches and apply directly, or request a warm intro."
**Courses**: "I linked a [DURATION]-minute module to your [SKILL] gap. Start it now and apply the learning in your next interview task."
**Pathways**: "I generated a direction analysis for your [ROLE] target. Review the pathway and save your chosen trajectory."
---
## Generated Task JSON Shapes
### Interview preview task
```json
{
"title": "Prepare your [ROLE] interview preview",
"subtitle": "[TYPE] round · [DURATION] minutes · [DIFFICULTY] pressure",
"serviceId": "interview-service",
"serviceName": "Interview service",
"cta": "Open interview preview",
"route": "/agents/interview/preview",
"previewParams": {
"role": "Product Manager",
"type": "behavioral",
"difficulty": "medium",
"duration": 5,
"source": "curator-v1"
},
"contextNarrative": "User needs confidence before real interviews.",
"subtasks": ["Confirm role", "Select round type", "Generate preview", "Complete practice", "Review feedback"],
"signals": ["interview.confidence", "communication_clarity", "role_alignment"],
"timebox": "15 minutes"
}
```
### Roleplay preview task
```json
{
"title": "Practice your [SCENARIO] conversation",
"subtitle": "[COUNTERPART] · [OUTCOME]",
"serviceId": "roleplay-service",
"serviceName": "Roleplay service",
"cta": "Open roleplay preview",
"route": "/agents/roleplay/preview",
"previewParams": {
"scenario": "salary_negotiation",
"counterpart": "recruiter",
"outcome": "agree_on_range",
"source": "curator-v1"
},
"contextNarrative": "User needs confidence before high-stakes conversation.",
"subtasks": ["Capture scenario", "Identify counterpart", "Define desired outcome", "Generate preview", "Practice", "Save script"],
"signals": ["negotiation_confidence", "communication_readiness", "salary_clarity"],
"timebox": "15 minutes"
}
```
### Agent-Social Branding task
```json
{
"title": "Draft your [TOPIC] post with agent",
"subtitle": "Agent suggests topic, drafts copy, optimizes timing",
"serviceId": "agent-social-branding",
"serviceName": "Agent-Social Branding",
"cta": "Draft post with agent",
"route": "/agents/social-branding",
"previewParams": {
"topic": "project_insight",
"platform": "linkedin",
"tone": "professional",
"source": "curator-v1"
},
"contextNarrative": "User has proof but no visibility. Agent builds inbound.",
"subtasks": ["Agent analyzes work", "Drafts post with hook", "User edits", "Agent schedules", "Track engagement"],
"signals": ["visibility", "profile_strength", "public_proof", "inbound_readiness"],
"timebox": "10 minutes"
}
```
### Job Matchmaking task
```json
{
"title": "Match with [N] aligned roles",
"subtitle": "Resume ready. Find high-fit opportunities.",
"serviceId": "job-matchmaking",
"serviceName": "Job Matchmaking",
"cta": "See matched roles",
"route": "/agents/matchmaking",
"previewParams": {
"searchType": "current_skills",
"limit": 5,
"source": "curator-v1"
},
"contextNarrative": "User has improved readiness. Time for active pipeline.",
"subtasks": ["Analyze resume vs roles", "Score top matches", "Surface warm intros", "Pre-draft applications", "Track pipeline"],
"signals": ["opportunity_awareness", "pipeline_health", "proactive_search", "application_readiness"],
"timebox": "10 minutes"
}
```
### Courses task
```json
{
"title": "Complete your [SKILL] skill module",
"subtitle": "[DURATION]-minute module · Progress tracked to Q Score",
"serviceId": "courses",
"serviceName": "Courses",
"cta": "Start skill module",
"route": "/agents/courses",
"previewParams": {
"skill": "sql_analytics",
"module": "fundamentals",
"duration": 15,
"source": "curator-v1"
},
"contextNarrative": "User has skill gap between current proof and target role.",
"subtasks": ["Identify skill gap", "Suggest targeted module", "Complete module", "Track in Q Score", "Apply in next task"],
"signals": ["skill_gap_closure", "course_completion", "readiness_improvement"],
"timebox": "15 minutes"
}
```
---
*End of examples document.*

107
curator-call-grip-sheet.md Normal file
View File

@@ -0,0 +1,107 @@
# GrowQR Curator — Call Grip Sheet
## 1. What the Curator Is (30-second pitch)
The Curator is a **deterministic growth operating system enriched by AI** — not a generic chatbot, not a hardcoded checklist.
- It classifies every user into an ICP, generates a 30/60/90-day plan, and serves **3 daily actions** (Measurement, Proof, Practice).
- Every task routes into a real service (Interview, Roleplay, Resume, Q Score, etc.) with a **one-click preview CTA** — no blank setup screens.
- AI only enriches copy and context; the backbone (ICP, stage routing, handoff logic) is deterministic and reproducible.
---
## 2. ICP Taxonomy (6 Segments)
| ICP | Trigger Signals | Default Plan | Sprint Theme |
|-----|-----------------|--------------|--------------|
| **Student / Recent Grad** | 0-2 yrs, before graduation, projects/skills | 30 days | "First Role Readiness" |
| **Intern** | Currently interning, return-offer focus | 30 days | "Intern-to-Offer" |
| **Fresher / Early Pro** | 0-5 yrs, no callbacks / weak interviews | 30 days | "Callback-to-Offer" |
| **Experienced Pro** | 5+ yrs, leadership/pay/scope goals | 60 days | "Leadership Readiness" |
| **Freelancer / Gig** | Clients, pricing, pipeline, trust | 60 days | "Client Pipeline" |
| **Founder / Solopreneur** | MVP, traction, fundraising, hiring | 90 days | "Founder Visibility & Validation" |
**Classifier is deterministic** — weighted scoring from onboarding answers, with AI only explaining the pick.
---
## 3. The 3-Column Daily Formula
Every day the user sees **exactly 3 tasks**:
| Column | Purpose | Typical Services |
|--------|---------|------------------|
| **Measurement** | Know where you stand | Q Score, Pathways, analytics |
| **Proof** | Create/improve evidence | Resume, Agent-Social Branding, portfolio |
| **Practice** | Rehearse real-world behavior | Interview, Roleplay, Courses, Matchmaking |
**Why this matters:** Users understand their day in one sentence — *"Today we measure the gap, improve one proof point, and practice the highest-leverage next move."*
---
## 4. The 7 Core Formulas
1. **ICP Classification** — weighted scoring from onboarding signals; AI explains, never overrides unless confidence is low.
2. **Plan Length** — 30 days for urgent career users, 60 for experienced/freelancer, 90 for founders.
3. **Stage Curriculum** — 6 stages (Baseline → Proof Build → Gap Fix → Practice Loop → Market Action → Conversion/Scale), mapped deterministically to days.
4. **Daily Task Selection** — pick one per column based on stage, blockers, service readiness, and Q Score impact.
5. **Service Priority Score**`0.25*stageFit + 0.20*blockerFit + 0.15*goalFit + 0.15*serviceReadiness + 0.10*freshness + 0.10*qScoreImpact + 0.05*effortFit`
6. **Minimum Context Handoff** — max 1 clarifying question before showing a CTA card with pre-filled preview params.
7. **Streak Completion** — meaningful events (interview completed, resume updated, course passed), not just page views.
---
## 5. Hard Rules (Non-Negotiable)
- **Never ask generic "What do you want to do?"** — first turn is service-aware and context-aware.
- **Max 1 clarifying question** before offering a default preview.
- **CTA card must persist** after subtask completion; never hide it.
- **No internal routes in chat text** — `/agents/...` URLs never appear in `reply`.
- **Deterministic routes only** — AI cannot invent routes, service IDs, or completion events.
- **Courses only when skill gap detected** — not when proof or practice is the blocker.
- **Matchmaking is active** — scoring, drafting, tracking, nudging — not passive browsing.
- **Social branding is agent-driven** — agent suggests topic, drafts copy, optimizes timing; user edits and approves.
- **ICP tone guardrails** — no student advice to experienced leaders; no job tasks to freelancers unless they want jobs.
---
## 6. Service Handoff Defaults
| Service | Min Context | Default Preview Params | CTA Copy |
|---------|-------------|------------------------|----------|
| **Interview** | role or round | `type=behavioral`, `difficulty=medium`, `duration=5` | "Open interview preview" |
| **Roleplay** | scenario or counterpart | `source=curator-v1` | "Open roleplay preview" |
| **Resume** | target role or proof item | — | "Open resume workspace" |
| **Agent-Social Branding** | topic or permission to suggest | `platform=linkedin`, `tone=professional` | "Draft post with agent" |
| **Job Matchmaking** | target role + search intent | `limit=5` | "See matched roles" |
| **Courses** | skill gap | `duration=15` | "Start skill module" |
| **Pathways** | direction question | — | "Review pathway" |
| **Q Score** | driver or baseline intent | — | "Review Q Score" |
---
## 7. The Operating Equation
```
User State + ICP Formula + Stage Curriculum + Service Readiness + Recent Signals
= Deterministic Daily Plan
Deterministic Daily Plan + AI Context Enrichment + Guardrails
= Personalized Curator Experience
```
---
## 8. What "Finished" Looks Like (Acceptance)
- Backend: `/v1/curator/chat` returns `handoff.actionRoute` with `/agents/interview/preview` (or roleplay/resume/etc.)
- Frontend: CTA card renders with eyebrow, title, subtitle, and service-specific button
- Product: every task connects back to the user's stated goal; 30/60-day plan framing is visible
- Streak: user clicks suggestion → chat → ≤2 turns → preview CTA → preview page → start service
- Prompt: externalized to `prompts/curator/daily-retention-system.md`, hot-reloadable without redeploy
---
## 9. One-Liner for the Call
> "The Curator is not a chatbot. It's a deterministic growth OS that knows who the user is, what stage they're in, and which 3 actions move them today. AI makes it feel personal; the formula makes it reliable. Every task ends in a service preview — not a blank setup screen — so users execute, not just plan."

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,455 @@
# GrowQR Curator — User Scenarios & Engagement State Machine
Date: 2026-06-19
Purpose: Map every user behavior pattern to Curator behavior, tasks, streak handling, and recovery logic.
---
## 1. Engagement States (User Behavior Patterns)
Think of the user as moving through these states, not just "active" or "inactive."
| State | Definition | Streak Status | Curator Priority |
|-------|-----------|---------------|------------------|
| **Ghost** | Signed up, never completed Day 1 | 0 | Re-activation: lower friction, simpler ask |
| **Day 1 Dropper** | Completed Day 1, never returned | 1 then 0 | Diagnose why: too hard? too vague? time? |
| **Streak Broken** | Had 3-7 day streak, then missed 2-7 days | Broken | Graceful recovery: don't shame, reduce load |
| **Streak Dead** | Broken for 14+ days | Dead | Soft reset: treat like Week 1, new baseline |
| **Sporadic** | Uses platform 1-2x/week, no streak | 0-2 | Lower daily load, bigger tasks when they show up |
| **Re-engaging** | Returning after 7+ days, clicking around | 0 | Acknowledge absence, one task max, no guilt |
| **Active** | 3-14 day streak, completes daily tasks | 3-14 | Full 3-column plan, maintain momentum |
| **Super-user** | 14+ day streak, all 3 columns complete | 14+ | Increase difficulty, introduce market-action tasks |
| **Conversion mode** | Active + real interviews/offers in flight | — | Emergency override: prioritize interview/roleplay |
| **Lost** | 30+ days no activity, no response to nudges | — | Archive plan, send "new sprint" offer |
---
## 2. Day-by-Day Progression (The Curator's Mindset)
### Day 1: The Hook
**User state:** Curious, low trust, high friction sensitivity.
**Curator behavior:**
- **Measurement:** Q Score baseline (5 min, max)
- **Proof:** Resume upload OR LinkedIn import (one click, not full audit)
- **Practice:** One warm-up interview (behavioral, easy, 3 min) OR skip if user seems overwhelmed
**Rules:**
- Show **only 1-2 tasks**, not 3. Third task is a bonus if they finish early.
- No long onboarding. Extract from signup data silently.
- First task must produce a visible artifact or feedback (score, feedback, draft).
- If user drops after first task: **Day 2 nudge is about the artifact, not the streak.**
**Example nudge:**
> "Your Q Score baseline is ready. You scored highest on [X], lowest on [Y]. Here's one move that closes the gap in 10 minutes."
---
### Day 2: The Habit Test
**User state:** Either hooked (returns easily) or testing (needs a reason).
**Curator behavior:**
- **Measurement:** Review Day 1 baseline, show one gap
- **Proof:** Resume headline rewrite OR first project proof point
- **Practice:** Interview or roleplay (still easy, 5 min)
**Rules:**
- If Day 1 was missed: **pick up where they left off, don't reset.**
- If Day 1 was completed: **reference the artifact.** "Your resume is uploaded. Let's fix the headline so recruiters see you."
- If Day 1 was completed but Day 2 is late: **reduce to 1 task, make it the most fun/valuable.**
---
### Day 3-7: The Build Phase
**User state:** Either forming habit or deciding to quit.
**Curator behavior:**
- Full 3-column plan kicks in.
- Tasks are **timeboxed (5-10 min)**. No 20-min tasks.
- **Practice column is interview/roleplay warm-up** — not hard rounds.
- **Proof column is resume bullets or LinkedIn headline** — not full rewrites.
**Rules:**
- If user misses 1 day: ignore, continue as if nothing happened.
- If user misses 2 days: next task is **1 task only, 5 min max.**
- If user misses 3 days: see "Streak Recovery" below.
---
### Day 8-14: The Gap-Fix Phase
**User state:** Habit forming or habit fragile.
**Curator behavior:**
- Tasks now reference prior work. "Your resume headline is fixed. Now let's turn one project into proof."
- **Practice gets harder.** Medium difficulty, 10 min.
- **Proof gets real.** First public post, first case study, first tailored resume.
**Rules:**
- If streak alive: introduce **weekly review task** (Day 7, Day 14) — "What changed this week?"
- If streak broken: see recovery logic.
---
### Day 15-21: The Practice Loop
**User state:** Habit locked or falling off.
**Curator behavior:**
- **Practice is the star.** 2-4 interviews/roleplays per week.
- **Proof is iteration.** Resume v2, profile polish, second post.
- **Measurement is Q Score check-in.** Show movement from Day 1.
**Rules:**
- If Q Score moved: celebrate. "Your communication score is up 12 points from Day 1."
- If Q Score didn't move: diagnose. "Your resume proof is better, but interview practice is still light. Let's fix that."
---
### Day 22-29: The Market Action Phase
**User state:** Ready to apply or already applying.
**Curator behavior:**
- **Practice:** Salary negotiation, recruiter screens, real interview prep.
- **Proof:** Tailored resume versions, application tracker, outreach drafts.
- **Measurement:** Application pipeline health, callback rate.
**Rules:**
- If user has no callbacks: return to proof + resume audit.
- If user has interviews: **emergency override.** All 3 tasks become interview/roleplay prep.
---
### Day 30: The Close
**User state:** Wants to see results.
**Curator behavior:**
- **30-day review artifact:** Day 1 vs Day 30 Q Score, proof created, interviews completed.
- **Next sprint:** Offer 3 options (continue, intensify, pivot).
- **Streak claim:** Visual reward, shareable, unlocks next ICP stage or advanced features.
---
### Day 31+: The Loop
**Curator behavior:**
- **Replan every 7 days.**
- If 30-day sprint was successful: **60-day sprint unlocks.** More advanced tasks, market-action heavy.
- If 30-day sprint was weak: **repeat the weak stage** (gap-fix, proof-build) with adjusted tone.
---
## 3. Scenario-by-Scenario Playbook
### Scenario A: Happy Path — Active User, Completes Daily
**Day 1:** Q Score baseline, resume upload, warm-up interview.
**Day 2:** Gap review, headline rewrite, behavioral interview.
**Day 3-7:** Project proof, recruiter roleplay, LinkedIn post.
**Day 8-14:** Resume audit, salary roleplay, application tracker.
**Day 15-21:** Interview replay, tailored resume, matchmaking.
**Day 22-29:** Real interview prep, offer negotiation, outreach.
**Day 30:** Review, next sprint selection.
**Curator tone:** Direct, momentum-driven. "This is your interview practice step for today."
**Streak:** Visual fire, increasing. Weekly milestone celebrations.
**Adaptation:** None needed. System is in maintenance mode.
---
### Scenario B: Ghost — Signed Up, Never Started Day 1
**Trigger:** 24h after signup, no Q Score baseline.
**Curator action:**
- Send **one nudge** via notification/email: "Your Q Score takes 3 minutes. Here's the link."
- If no response in 48h: **reduce ask.** "Just upload your resume. One click."
- If no response in 72h: **change channel.** Send a WhatsApp/SMS if available.
- If no response in 7 days: **archive.** Mark as "cold." Re-engage in 14 days with "New sprint ready."
**Curator tone:** Helpful, zero pressure. No streak guilt.
**Task count:** 1 task max.
**Recovery:** On return, treat as Day 1 but skip onboarding. Resume from last known state.
---
### Scenario C: Day 1 Dropper — Did Day 1, Never Returned
**Trigger:** 48h after Day 1 completion, no Day 2 activity.
**Curator action:**
- Nudge references **Day 1 artifact.** "Your Q Score showed a communication gap. One practice fixes it."
- Offer **same task type, slightly easier.** If Day 1 was interview, Day 2 nudge is a 3-min warm-up.
- If no response in 72h: **ask why.** One question: "What stopped you: time, confusion, or not relevant?"
- If they answer: **adapt plan.**
- "Time" → 5-minute tasks only.
- "Confusion" → simpler tasks, more guidance.
- "Not relevant" → re-ICP or replan.
**Curator tone:** Curious, not accusatory. "What would make this useful?"
**Streak:** 1. Treat as broken streak recovery.
---
### Scenario D: Streak Broken — 3-7 Days of Silence
**Trigger:** Missed 3 days after active streak.
**Curator action:**
- **Day 1 of return:** 1 task only. 5 minutes. No mention of missed days unless they bring it up.
- **Task:** Resume headline fix OR interview warm-up — something they already know how to do.
- **Day 2 of return:** 2 tasks. Reference the Day 1 return: "Back to building. Let's fix one proof point."
- **Day 3 of return:** Full 3 tasks. Resume normal plan.
**Curator tone:** Welcoming, no guilt. "Pick up where you left off."
**Streak:** Reset to 1 on return. Don't show broken streak flame.
**Recovery speed:** 3 days to full plan.
---
### Scenario E: Streak Dead — 14+ Days of Silence
**Trigger:** 14 days no activity.
**Curator action:**
- **Soft reset.** Treat as new 30-day sprint, but skip onboarding.
- **Day 1:** New Q Score baseline (or review old one). "Here's where you stand today."
- **Day 2:** One proof task, one practice task. Not 3.
- **Week 1:** Rebuild trust. Tasks must produce visible wins.
- **If no return after 14 days:** Send "Your new sprint is ready" message. Highlight one changed thing (e.g., new job market data, new interview template).
**Curator tone:** Fresh start. "New sprint. New target. Same goal."
**Streak:** 0. Start over.
**Plan:** Re-run ICP classifier if onboarding data is stale.
---
### Scenario F: Sporadic — 1-2x/Week, No Streak
**User archetype:** Busy, platform is a tool not a habit.
**Curator action:**
- **Don't optimize for streak.** Optimize for value per session.
- **When they show up:** Give them **the highest-impact 1 task** from their current stage.
- **Don't give 3 tasks.** They won't do them. Give 1, with a "next time" teaser.
- **Tasks are bigger:** 15-20 min, not 5 min. Since they come rarely, they need bigger wins.
- **Example:** "You haven't practiced in 5 days. You have a real interview coming up. Here's a 10-minute roleplay."
**Curator tone:** Respects their time. "This is the one move for this week."
**Streak:** Don't show streak UI. Show "last session [X] days ago" and "this week: 1 task done."
**Plan:** Weekly plan, not daily plan. 3 tasks per week, not per day.
---
### Scenario G: Re-engaging — Returning After 7+ Days, Browsing
**Trigger:** User opens app after 7+ days, clicks around but doesn't complete tasks.
**Curator action:**
- **Detect browsing.** If they open but don't start a task within 2 min: trigger a chat bubble.
- **Chat:** "Welcome back. What changed since you were last here?" (job, timeline, goal, nothing)
- **If they say nothing:** "Your Q Score was [X]. One thing improved it since then: [task]. 5 minutes."
- **If they say goal changed:** Re-ICP, replan, Day 1 of new sprint.
- **If they say timeline moved:** Adjust urgency, plan length.
**Curator tone:** Warm, acknowledging. "Good to see you."
**Task:** 1 task max. Make it the one they abandoned last time.
---
### Scenario H: Super-user — 14+ Day Streak, All 3 Columns
**Curator action:**
- **Introduce harder tasks.** Hard interview mode, executive roleplay, leadership case study.
- **Introduce market-action tasks.** Apply to real roles, send recruiter outreach, schedule real interviews.
- **Introduce cross-service tasks.** "Practice this interview, then turn the answer into a LinkedIn post."
- **Unlock 60-day plan.** "You've completed 30 days. Ready for the conversion sprint?"
- **Add variety.** Alternate interview types, alternate roleplay scenarios. Prevent boredom.
**Curator tone:** Partner, not coach. "You're ready for the real thing. Let's go."
**Streak:** Celebrate 7, 14, 21, 30. Visual badges.
**Plan:** 60-day or 90-day plan. More self-directed options.
---
### Scenario I: Conversion Mode — Has Real Interview/Offer in Flight
**Trigger:** User inputs interview date, or matchmaking tracks application.
**Curator action:**
- **Emergency override.** All 3 tasks become interview/roleplay prep.
- **Measurement:** Q Score gap for that specific role.
- **Proof:** Tailored resume for that company.
- **Practice:** Interview or roleplay for that exact scenario.
- **Countdown:** "Interview in 3 days. Today: behavioral round. Tomorrow: roleplay the salary."
**Curator tone:** Urgent, focused. "This is your prep. Nothing else matters."
**Streak:** Pause normal streak. Create "interview prep streak" sub-streak.
**Plan:** Frozen. All resources directed to interview prep.
---
### Scenario J: Lost — 30+ Days, No Response to Nudges
**Curator action:**
- **Archive current plan.**
- **Send final nudge:** "Your 30-day plan is paused. Start a new sprint when you're ready."
- **Re-engagement trigger:** New feature, new job market signal, new season, or user-initiated.
- **On return:** Full soft reset. New Day 1. Ask if goal changed.
**Curator tone:** Neutral, door open. "When you're ready."
**Streak:** 0. Plan archived.
---
## 4. State Machine Diagram (Text)
```
SIGNUP
|
+--> [Day 1 complete] --> ACTIVE (Day 2)
| |
| +--> [Daily completion] --> STREAK (Day 3-7)
| | |
| | +--> [Continues] --> BUILD (Day 8-14)
| | | |
| | | +--> [Continues] --> LOOP (Day 15-21)
| | | | |
| | | | +--> [Continues] --> MARKET (Day 22-29)
| | | | | |
| | | | | +--> [Day 30] --> REVIEW (Day 31+)
| | | | | |
| | | | | +--> [Miss 3 days] --> BROKEN
| | | | | |
| | | | | +--> [Miss 14 days] --> DEAD
| | | | | |
| | | | | +--> [Has interview] --> CONVERSION
| | | | | |
| | | | | +--> [14+ streak] --> SUPER
| | | | |
| | | | +--> [Miss 3 days] --> BROKEN
| | | |
| | | +--> [Miss 2 days] --> BROKEN (early)
| | |
| | +--> [Miss 1 day] --> ACTIVE (no change)
| |
| +--> [Day 1 missed] --> GHOST
| |
| +--> [Return in 24h] --> ACTIVE (Day 1)
| |
| +--> [Return in 7d] --> RE-ENGAGING (Day 1)
| |
| +--> [No return] --> LOST
|
+--> [Day 1 partial] --> DAY 1 DROPPER
|
+--> [Return in 48h] --> ACTIVE (Day 2)
|
+--> [No return] --> GHOST
BROKEN
|
+--> [Return] --> RECOVERY (1 task, 5 min)
| |
| +--> [Day 2] --> RECOVERY (2 tasks)
| |
| +--> [Day 3] --> ACTIVE (full 3 tasks)
|
+--> [No return 14 days] --> DEAD
DEAD
|
+--> [Return] --> SOFT RESET (new Day 1)
|
+--> [No return 30 days] --> LOST
SUPER
|
+--> [Miss 1 day] --> ACTIVE (still)
|
+--> [Miss 3 days] --> BROKEN
|
+--> [Interview in flight] --> CONVERSION
CONVERSION
|
+--> [Interview done] --> ACTIVE or MARKET
|
+--> [Offer received] --> NEGOTIATION (new sub-mode)
|
+--> [Rejected] --> ACTIVE (comfort + rebuild)
SPORADIC (orthogonal, can enter from any state)
|
+--> [Weekly session] --> 1 big task
|
+--> [Increasing frequency] --> ACTIVE
```
---
## 5. Curator Tone Matrix by State
| State | Tone | Example Opening |
|-------|------|-----------------|
| Ghost | Invitation, zero pressure | "Your Q Score takes 3 minutes. Ready when you are." |
| Day 1 Dropper | Curious, artifact-focused | "Your resume is uploaded. Let's fix the headline." |
| Broken | Welcoming, no guilt | "Pick up where you left off. One task, 5 minutes." |
| Dead | Fresh start, optimistic | "New sprint. New target. Same goal." |
| Sporadic | Respectful, high-value | "This is the one move for this week." |
| Re-engaging | Warm, acknowledging | "Good to see you. What's changed?" |
| Active | Direct, momentum | "This is your practice step for today." |
| Super | Partner, challenger | "You're ready for the real thing. Let's go." |
| Conversion | Urgent, focused | "Interview in 3 days. Here's today's prep." |
| Lost | Neutral, door open | "When you're ready, start a new sprint." |
---
## 6. Task Count Rules by State
| State | Tasks per Day | Time per Task | Total Time |
|-------|---------------|---------------|------------|
| Ghost / Day 1 Dropper | 1 | 3-5 min | 5 min |
| Re-engaging / Recovery | 1 | 5 min | 5 min |
| Sporadic | 1 | 15-20 min | 20 min |
| Active | 3 | 5-10 min | 15-30 min |
| Super | 3 | 10-20 min | 30-45 min |
| Conversion | 3 | 10-15 min | 30-45 min |
---
## 7. Nudge Strategy by State
| State | Nudge Timing | Channel | Content |
|-------|-------------|---------|---------|
| Ghost | 24h, 48h, 72h | In-app, email, WhatsApp | Artifact reference, reduced ask |
| Day 1 Dropper | 48h, 72h | In-app, push | "Your Q Score showed [X]. One move fixes it." |
| Broken | 24h after return | In-app | "Welcome back. One task." |
| Dead | 7d, 14d, 30d | Email, WhatsApp | "New sprint ready." / "Your market changed." |
| Sporadic | Weekly | Push | "This week's one move: [task]." |
| Active | Daily | In-app | Daily plan + streak fire |
| Super | Weekly | In-app | "30 days complete. Next sprint unlocked." |
| Conversion | Daily | In-app, push, WhatsApp | Countdown + specific prep task |
| Lost | 30d, 60d | Email | "Start a new sprint." |
---
## 8. Summary: The 10 Scenarios at a Glance
| Scenario | Core Principle | Curator's Job |
|----------|---------------|---------------|
| A. Happy path | Maintain momentum | 3 tasks/day, celebrate, escalate difficulty |
| B. Ghost | Reduce friction | 1 tiny task, multiple channels, artifact hook |
| C. Day 1 dropper | Diagnose and adapt | Ask why, adjust plan, reduce or refocus |
| D. Streak broken | Graceful recovery | 1 task, no guilt, 3-day ramp back |
| E. Streak dead | Soft reset | New Day 1, skip onboarding, rebuild trust |
| F. Sporadic | Value per session | 1 big task/week, no streak pressure |
| G. Re-engaging | Acknowledge and pivot | Chat bubble, ask what changed, 1 task |
| H. Super-user | Challenge and unlock | Harder tasks, 60-day plan, market action |
| I. Conversion | Emergency override | All tasks → interview prep, countdown |
| J. Lost | Door open | Archive, final nudge, wait for return |
---
*End of scenarios document.*

463
delivery-map.md Normal file
View File

@@ -0,0 +1,463 @@
# GrowQR Delivery Map — June 3, 2026
> **Goal:** Ship a testable GrowQR dashboard + backend to AVPS in one session. Team should be able to log in, start a workflow, chat with the agent, open service pages, and see analytics.
---
## 1. Repo Landscape
| Repo | Role | Status |
|---|---|---|
| `growqr-backend` | Production backend (Hono + Rivet + Drizzle + AI SDK) | Active development |
| `growqr-dashboard` | **Target dashboard UI** (Next.js 14 + Clerk + Tailwind) | Mock data — needs API integration |
| `growqr-next-frontend` | **Reference only** — has v2/v3 UI we can borrow from | Abandoned as primary frontend |
| `growqr-app/frontend` | **Reference only** — production interview/roleplay/resume components | Still in production separately |
**Rule:** All new UI goes into `growqr-dashboard`. Other repos are read-only reference.
---
## 2. Backend Current State
### What already works
- Clerk-authenticated Hono routes
- Rivet actor registry with per-user `userActor`, per-run `workflowRunActor`, and service actors (`interviewServiceActor`, `roleplayServiceActor`, `resumeServiceActor`)
- Workflow registry with 5 sellable workflow definitions
- Database tables: `workflowRuns`, `workflowRunModules`, `workflowEvents`, `workflowArtifacts`, `workflowApprovals`, `qscoreSnapshots`
- Service adapters for resume, interview, roleplay, Q Score
- Chat route with LLM fallback + tool dispatch (start interview, start roleplay, analyze resume, compute qscore)
- Gitea per-user repo model
- OpenCode container lifecycle
- Prompt/agent markdown loading
### Backend API surface
```
GET /workflows — list all workflow definitions
GET /workflows/:workflowId — get single workflow definition
POST /workflows/:workflowId/runs — start a workflow run
GET /workflows/:workflowId/runs/current — get current run for workflow
GET /workflows/capabilities/services — list service capabilities
GET /workflows/capabilities/health — health check all services
GET /workflows/runs/history — user's run history
GET /workflows/validate — validate all workflow defs
GET /workflow-runs/:runId — full run detail (modules, artifacts, events)
POST /workflow-runs/:runId/pause — pause run
POST /workflow-runs/:runId/resume — resume run
POST /workflow-runs/:runId/run — run all modules until next gate
POST /workflow-runs/:runId/modules/:moduleId/run — run single module
GET /workflow-runs/:runId/artifacts — list artifacts
GET /workflow-runs/:runId/artifacts/:id/content — read artifact content
GET /workflow-runs/:runId/events — list events
POST /workflow-runs/:runId/approvals/:id — approve/reject gate
POST /chat — chat with Grow Agent
# Legacy compat aliases
GET /workflows/job-application
POST /workflows/job-application
POST /workflows/job-application/pause
POST /workflows/job-application/resume
POST /workflows/job-application/agents/:moduleId/run
POST /workflows/job-application/agents/:moduleId/score
```
### 5 Sellable Workflows
| ID | Title | Urgency | Duration | Modules |
|---|---|---|---|---|
| `interview-to-offer` | Interview-to-Offer Accelerator | High | 25 days | resume → interview-plan → sara → emily → qscore |
| `career-transition` | Career Transition Sprint | Medium | 12 weeks | transition-map → resume |
| `salary-negotiation-war-room` | Salary Negotiation War Room | High | 2472 hrs | negotiation-script → emily |
| `promotion-readiness` | Promotion Readiness Packet | Medium | 1 week | evidence-packet → emily |
| `personal-brand-opportunity-engine` | Personal Brand Opportunity Engine | Low | 1 week | profile-rewrite |
### What the backend still needs today
- Verify build/typecheck passes
- Verify all routes respond locally
- Add clean analytics/Q Score summary endpoint if missing
- Ensure service actors work for Q Score
- Smoke-test workflow creation → module run
- Confirm env vars are correct for AVPS deploy
---
## 3. Dashboard Current State
### Existing pages (all using mock data)
```
app/page.tsx — Home
app/analytics/page.tsx — Analytics
app/community/page.tsx — Community
app/events/page.tsx — Events
app/features/page.tsx — Features (available/active tabs)
app/features/[id]/page.tsx — Feature detail
app/mentor/page.tsx — Mentor
app/pathways/page.tsx — Pathways
app/productivity/page.tsx — Productivity
app/rewards/page.tsx — Rewards
app/settings/page.tsx — Settings
app/social/page.tsx — Social
app/suggestions/page.tsx — Suggestions
app/workflows/page.tsx — Workflows (available/active tabs)
app/workflows/[id]/page.tsx — Workflow detail
```
### Dashboard components
```
components/AppShell.tsx
components/ModuleHeader.tsx
components/ActiveWorkflowDetail.tsx
components/AvailableWorkflowCard.tsx
components/PromptBar.tsx
```
### Dashboard design system
- Tailwind with custom theme (`brand-orange`, `ink`, `surface-rail`, etc.)
- `rounded-tile` pattern for cards
- Day simulation via `useDay()` for demo progression
### What the dashboard needs today
1. **API layer** — typed client to backend (replace mock `getWorkflows`, `getFeatures`, etc.)
2. **API proxy**`app/api/growqr/[...path]/route.ts` to avoid CORS issues
3. **Workflows page** — wire to real backend
4. **Workflow detail** — add mission state sidebar + workflow chat
5. **Talk to Me chat** — new chat page with streaming-ish UI
6. **Feature pages** — port interview/roleplay/resume/Q Score from other repos
7. **Analytics** — merge Q Score + career performance data
---
## 4. Reference UI Sources
### From `growqr-next-frontend`
| What | Source Path | Use For |
|---|---|---|
| v3 Workflows layout | `src/app/v3/workflows/page.tsx` | Workflow page layout with slim sidebar |
| v3 Workflow detail | `src/app/v3/workflows/interview-to-offer/page.tsx` | Active workflow detail pattern |
| v2 Services (already ported) | `src/app/v2/services/interview/*` | Interview/roleplay/resume pages |
| Q Score | `src/app/qx-score/page.tsx`, `src/app/v2/qx-score/page.tsx` | Analytics/Q Score UI |
| Chat route | `src/app/api/chat/route.ts` | Streaming chat backend pattern |
| Auth flow | `src/app/auth/*` | Career profile, goals, onboarding |
### From `growqr-app/frontend`
| What | Source Path | Use For |
|---|---|---|
| Interview components | `src/components/interview/*` | LiveAvatarVideo, CoachingBanner, EquipmentCheck, etc. |
| Interview pages | `src/app/(dashboard)/upskilling/interview/*` | Setup, preview, feedback |
| Roleplay components | `src/components/roleplay/*` | LiveAvatarVideo, RoleplayLaunchOverlay, FeedbackDashboard |
| Resume components | `src/components/resume/*` | ResumeUpload, ResumeCard, ResumePreviewModal, TemplateGallery |
| Interview hooks | `src/hooks/useInterview*.ts` | Session, media, review, recording hooks |
| Interview lib | `src/lib/interview/*` | Types, API helpers |
---
## 5. Execution Plan — 6 Hours
### Phase 1: Stabilize & Map (0:000:30)
**Goal:** Know exactly what's broken before touching UI.
- [ ] Run `growqr-backend` build + typecheck
- [ ] Run `growqr-dashboard` build
- [ ] Check envs: backend URL, Clerk keys, service URLs, AVPS deploy env
- [ ] Confirm backend routes respond locally (`/workflows`, `/chat`, etc.)
- [ ] Document short failure list
**Deliverable:** Known broken things list. No UI changes yet.
---
### Phase 2: Dashboard API Layer (0:301:30)
**Goal:** Dashboard can talk to backend instead of mock data.
Create in `growqr-dashboard`:
```
lib/api.ts — Base fetch wrapper with auth
lib/growqr-api.ts — Typed API client
types/workflows.ts — Workflow/run/module types
types/chat.ts — Chat message types
app/api/growqr/[...path]/route.ts — Next.js API proxy
```
Client methods needed:
```ts
listWorkflows()
getWorkflow(id)
startWorkflow(workflowId, goal?, input?)
getCurrentRun(workflowId)
getWorkflowRun(runId)
runWorkflow(runId)
runModule(runId, moduleId)
pauseRun(runId)
resumeRun(runId)
sendChat(messages)
getRunArtifacts(runId)
getRunEvents(runId)
approveGate(runId, approvalId, status)
```
**Deliverable:** Dashboard fetches real workflow data from backend.
---
### Phase 3: Workflows Page MVP (1:302:30)
**Goal:** Workflows become real product pages.
Update these files:
```
app/workflows/page.tsx — Wire to real API
app/workflows/[id]/page.tsx — Wire to real API
components/AvailableWorkflowCard.tsx — Show real workflow data
components/ActiveWorkflowDetail.tsx — Show real run state
```
Required behavior:
- Available tab lists 5 backend workflows with real data
- Each card shows: promise, modules, duration, price, "Start workflow" button
- Starting a workflow calls `POST /workflows/:workflowId/runs`
- Active section calls `GET /workflows/:workflowId/runs/current`
- Detail page layout:
- Left: slim workflow nav
- Top: current workflow title + status bar
- Center: workflow chat / work area
- Right: mission state (modules, artifacts, events, approvals)
**Deliverable:** User can start and view a workflow from the dashboard.
---
### Phase 4: Chat Surfaces (2:303:30)
**Goal:** Product feels agentic with two chat surfaces.
#### A. Global "Talk to Me" Chat
New page:
```
app/talk/page.tsx (or app/chat/page.tsx)
```
Purpose:
- Agent discovery & workflow recommendation
- Starting workflows from conversation
- Pulling workflow status
- User preferences & memory
- General career questions
Backend: `POST /chat`
UI should show:
- Streaming-like assistant response (staged states if not truly streaming)
- Tool/session cards when backend returns sessions
- Workflow suggestion/action buttons when backend recommends one
- Progressive states: "Reading memory…" → "Checking workflows…" → "Thinking…" → response
#### B. Workflow-Specific Chat
Inside `app/workflows/[id]/page.tsx`:
- "Run next step", "Show status", "Launch interview", "Open artifact", "Approve plan"
- Calls same `/chat` with workflow context prepended
- Shows module execution results inline
**Deliverable:** Both chat surfaces are functional and connected to backend.
---
### Phase 5: Feature/Service Pages (3:304:45)
**Goal:** Feature cards route to working service UIs.
New pages in dashboard:
```
app/features/resume/page.tsx
app/features/interview/page.tsx
app/features/roleplay/page.tsx
app/features/qscore/page.tsx
```
Port strategy (in priority order):
1. **Interview** — from `growqr-app/frontend/src/components/interview/*` + `growqr-next-frontend/src/app/v2/services/interview/*`
2. **Roleplay** — from `growqr-app/frontend/src/components/roleplay/*` + `growqr-next-frontend/src/app/v2/services/roleplay/*`
3. **Resume** — from `growqr-app/frontend/src/components/resume/*` + `growqr-next-frontend/src/app/v2/services/resume/*`
4. **Q Score** — from `growqr-next-frontend/src/app/v2/qx-score/*`
Shortcut approach:
- Create dashboard-compatible wrappers, not perfect ports
- Missing backend data → clean empty/loading states
- Support workflow query params: `?workflowRunId=...&moduleId=...`
**Deliverable:** Feature cards open functional service pages.
---
### Phase 6: Q Score + Analytics (4:455:30)
**Goal:** Coherent analytics page with real data where available.
Merge from:
- `growqr-dashboard/app/analytics/page.tsx` (existing)
- `growqr-next-frontend/src/app/qx-score/page.tsx`
- `growqr-next-frontend/src/app/v2/qx-score/page.tsx`
Minimum analytics sections:
- Current Q Score (gauge/number)
- Baseline vs Latest comparison
- Workflow progress contribution
- Readiness dimension breakdown
- Recent sessions/events timeline
- Recommended next action
Backend data sources:
- `workflowRuns.qscoreBefore` for baseline
- `qscoreSnapshots` table for history
- `/workflow-runs/:runId` for module progress
- Add `GET /analytics/summary` endpoint if needed
**Deliverable:** Analytics page shows real Q Score + workflow progress.
---
### Phase 7: Build, Fix, Deploy (5:306:15)
**Goal:** Everything builds, deploys, and team can test.
- [ ] `cd growqr-backend && bun run typecheck && bun run build`
- [ ] `cd growqr-dashboard && pnpm build`
- [ ] Fix only blockers: type errors, missing imports, env names, auth/proxy
- [ ] Deploy to AVPS
- [ ] Send test links + testing checklist to team
**Deliverable:** Deployed link on AVPS.
---
## 6. Hard Cuts — What We Are NOT Doing Today
To finish in 6 hours, we explicitly skip:
- Homepage rethink / redesign
- Full billing / entitlement / SKU enforcement
- True streaming protocol (SSE/WebSocket) — simulate with staged UI
- Complete service UI parity with `growqr-app`
- Deep memory/conversation history UI
- Advanced workflow graph animations
- New backend architecture changes
- Moving/cleaning all three repos
- Community, events, social, rewards, productivity, mentor, pathways, suggestions pages
- Mobile responsiveness polish
- E2E tests
---
## 7. MVP Acceptance Checklist
By end of session, team should be able to test all of these:
- [ ] **Auth:** Login works with Clerk
- [ ] **Workflows page:** Lists 5 workflows from backend
- [ ] **Start workflow:** User can start Interview-to-Offer
- [ ] **Active workflow:** Detail page shows modules/state/events
- [ ] **Run module:** User can trigger at least one module
- [ ] **Talk to Me chat:** Responds to messages, can suggest/trigger workflows
- [ ] **Workflow chat:** Exists inside workflow detail page
- [ ] **Features page:** Opens Interview, Roleplay, Resume, Q Score
- [ ] **Analytics:** Shows Q Score and workflow progress
- [ ] **Deploy:** Dashboard builds and deploys to AVPS
- [ ] **Team test link:** Sent with testing instructions
---
## 8. Implementation Priority Order
If time runs short, do these in exactly this order:
1. Dashboard API proxy + typed client
2. Real workflows list / start / current-run
3. Workflow detail shell with mission state + chat
4. Global Talk-to-Me chat page
5. Feature page routing to service pages
6. Q Score / analytics page
7. Build / deploy / test links
---
## 9. Key Files Reference
### Backend
```
growqr-backend/src/index.ts — App entry
growqr-backend/src/config.ts — Env config
growqr-backend/src/actors/registry.ts — Rivet actor registry
growqr-backend/src/actors/user-actor.ts — Per-user actor
growqr-backend/src/actors/workflow-run-actor.ts — Per-run actor
growqr-backend/src/actors/product-service-actors.ts — Service actors
growqr-backend/src/routes/workflows.ts — Workflow + run routes
growqr-backend/src/routes/chat.ts — Chat route
growqr-backend/src/routes/services.ts — Service routes
growqr-backend/src/workflows/registry.ts — 5 workflow definitions
growqr-backend/src/workflows/module-runner.ts — Module execution
growqr-backend/src/workflows/types.ts — Workflow types
growqr-backend/src/db/schema.ts — Database schema
growqr-backend/src/agents/catalog.ts — Agent catalog + prompts
```
### Dashboard
```
growqr-dashboard/app/layout.tsx — Root layout
growqr-dashboard/app/page.tsx — Home
growqr-dashboard/app/workflows/page.tsx — Workflows list
growqr-dashboard/app/workflows/[id]/page.tsx — Workflow detail
growqr-dashboard/app/features/page.tsx — Features list
growqr-dashboard/app/features/[id]/page.tsx — Feature detail
growqr-dashboard/app/analytics/page.tsx — Analytics
growqr-dashboard/components/AppShell.tsx — Shell + sidebar
growqr-dashboard/components/PromptBar.tsx — Chat input bar
growqr-dashboard/middleware.ts — Clerk middleware
growqr-dashboard/lib/state.ts — Day simulation state
growqr-dashboard/data/workflows.ts — Mock workflow data (TO REPLACE)
growqr-dashboard/data/features.ts — Mock feature data (TO REPLACE)
```
### Reference (read-only)
```
growqr-next-frontend/src/app/v3/workflows/* — Workflow UI pattern
growqr-next-frontend/src/app/v2/services/interview/* — Interview pages
growqr-next-frontend/src/app/v2/services/roleplay/* — Roleplay pages
growqr-next-frontend/src/app/v2/services/resume/* — Resume pages
growqr-next-frontend/src/app/v2/qx-score/* — Q Score UI
growqr-next-frontend/src/app/api/chat/route.ts — Chat streaming pattern
growqr-app/frontend/src/components/interview/* — Production interview components
growqr-app/frontend/src/components/roleplay/* — Production roleplay components
growqr-app/frontend/src/components/resume/* — Production resume components
growqr-app/frontend/src/hooks/useInterview*.ts — Interview hooks
growqr-app/frontend/src/lib/interview/* — Interview lib
```

86
dev-test-account.md Normal file
View File

@@ -0,0 +1,86 @@
# Dev Test Account
## Credentials
| Field | Value |
|----------|--------------------------|
| Email | test@test.com |
| Password | Violet-Mountain-97!qR |
| User ID | user_3EXAwsYrQ6WtQgxjaJtxVTEWYqz |
## How the account was created
### 1. Create user in Clerk
```bash
cd growqr-next-frontend
node - <<'NODE'
const { createClerkClient } = require("@clerk/backend");
const fs = require("fs");
const secretKey = fs.readFileSync(".env.local", "utf8").match(/^CLERK_SECRET_KEY=(.*)$/m)[1].trim();
const clerk = createClerkClient({ secretKey });
(async () => {
const email = "test@test.com";
const password = "Violet-Mountain-97!qR";
const existing = await clerk.users.getUserList({ emailAddress: [email] });
if (existing.data?.[0]) {
console.log("already exists:", existing.data[0].id);
return;
}
const user = await clerk.users.createUser({
emailAddress: [email],
password,
firstName: "Test",
lastName: "User",
skipPasswordChecks: true,
});
console.log("created:", user.id, email);
})();
NODE
```
### 2. Mirror user into local Postgres
```bash
cd growqr-backend
docker compose exec -T postgres psql -U growqr -d growqr -c \
"INSERT INTO users (id, email, display_name)
VALUES ('user_3EXAwsYrQ6WtQgxjaJtxVTEWYqz', 'test@test.com', 'Test User')
ON CONFLICT (id) DO UPDATE SET email = EXCLUDED.email, display_name = EXCLUDED.display_name, updated_at = now();"
```
## Logging in without email verification (dev token)
Clerk enforces email verification on sign-in. For dev, generate a sign-in token
and open it directly in the browser:
```bash
cd growqr-next-frontend
TOKEN=$(node -e '
const { createClerkClient } = require("@clerk/backend");
const fs = require("fs");
const secretKey = fs.readFileSync(".env.local", "utf8").match(/^CLERK_SECRET_KEY=(.*)$/m)[1].trim();
const clerk = createClerkClient({ secretKey });
(async () => {
const userId = (await clerk.users.getUserList({ emailAddress: ["test@test.com"] })).data[0].id;
const t = await clerk.signInTokens.createSignInToken({ userId, expiresInSeconds: 3600 });
process.stdout.write(t.token);
})();
')
open "http://localhost:3000/auth/signin?__clerk_ticket=$TOKEN"
```
This signs in as **Test User** and redirects to `/v2`.
## Notes
- Clerk is in **development mode** (test instance: `noted-elephant-23`).
- `skipPasswordChecks: true` bypasses breach-detection (the first password
`Test1234!` was rejected as compromised).
- The sign-in token flow avoids the email code verification step entirely.
- Token expires after 1 hour; re-run the command to get a fresh one.

849
event flow.md Normal file
View File

@@ -0,0 +1,849 @@
> **Missions are not chat flows. Missions are event-driven product journeys.**
> Chat/Grow Agent is only one optional surface that can read mission state and help the user decide what to do next.
The mission dashboard should work even if the user never opens chat.
I read the Rivet docs you linked, the current backend mission/actor code, the old `growqr-app/orchestrator`, and the service event patterns. The correct production design is a **mission event system + dashboard projection**, not a chat-first workflow.
---
# Revised product model
## User buys a mission
Example:
> **Interview-to-Offer Accelerator — $10/month**
Includes limits like:
- 10 mock interviews/month
- X resume analyses/optimizations
- maybe 1 final readiness report
- optional add-ons later: roleplay, extra interviews, video analysis, etc.
After purchase, the user gets an **active mission dashboard**.
The dashboard shows:
- current mission progress
- next required action
- completed service actions
- generated artifacts
- interview/resume results
- Q Score/readiness trend
- quota usage
- recommendations
Chat can help, but the dashboard is the primary surface.
---
# Important correction for Interview-to-Offer
If the team says this mission currently uses only:
- Resume
- Interview
Then dont force Roleplay into the core package.
Roleplay can become:
1. an upsell,
2. a recommended recovery action,
3. a premium variant,
4. or a later stage only if interview results show communication weakness.
So the core mission becomes:
## Interview-to-Offer Accelerator v1
### Included services
- Resume Building
- Mock Interview
- Q Score/readiness analytics
- Grow Agent/planning only as backend intelligence, not necessarily chat
### Core stages
1. Purchase / mission activated
2. Resume uploaded or selected
3. Resume analyzed/improved for target interview
4. Interview prep plan generated
5. Mock interview configured
6. Mock interview completed
7. Review received
8. Final readiness score/report generated
That is much cleaner.
---
# What exists today
From the code:
## Backend already has
- `grow_active_missions`
- mission actors like `interviewToOfferMissionActor`
- mission snapshots
- explicit APIs to update stages and artifacts
- PG-first persistence for active missions
- Q Score snapshots/workflow event tables from older workflow infra
But right now, mission progress updates mostly happen through explicit backend calls like:
```txt
POST /missions/active/:instanceId/stages/:stageId
POST /missions/active/:instanceId/artifacts
```
That means the dashboard does not automatically know when a microservice finishes something unless we explicitly update the mission.
## Old orchestrator already had a useful pattern
The old `growqr-app/orchestrator`:
- routes actions to services
- receives `agent_data` messages
- extracts Q Score signals from service results
- publishes signals to `qscore.signal_events`
- handles real-time score updates
But it has too much routing registry logic:
```py
ACTION_TO_AGENT
PAGE_TO_AGENT
COMPOSITE_WORKFLOWS
```
We should not rebuild that as another large registry.
## Services emit useful events/messages already
Examples:
Resume emits A2A-style messages:
- `resume_created`
- `resume_loaded`
- `version_saved`
- `ai_analysis_complete`
- `ai_summary_optimized`
- `ai_skills_suggested`
- `export_ready`
Interview emits:
- `interview_configured`
- `session.completed` over live WS
- review endpoint returns `completed`, `processing`, `failed`, `not_eligible`
- `review_loaded` through agentic path
Roleplay emits similar patterns.
Q Score already has a strong event ingestion path:
```txt
qscore.signal_events Redis stream
```
So the missing layer is not “service capability.” It is a **GrowQR mission event ingestion/projection layer**.
---
# Correct architecture
## Principle
> Postgres is the source of truth. Actors are live reducers/projectors. Chat is just one consumer.
## Event flow
```txt
Service action happens
GrowQR backend receives/creates event
Raw event is stored in Postgres event inbox
Event is forwarded to the relevant mission actor
Mission actor updates mission snapshot/progress/artifacts
Dashboard reads updated mission snapshot
Q Score signals are published/updated
Grow/chat may optionally read the same state
```
---
# New concept: dynamic mission events
We do **not** need a rigid event registry.
We need one flexible event envelope.
## Generic event envelope
```ts
type GrowEvent = {
id: string;
userId: string;
orgId?: string;
source: string;
// resume-service, interview-service, roleplay-service, qscore-service, grow-backend
type: string;
// resume.ai_analysis_complete
// interview.session_completed
// interview.review_completed
// mission.purchased
// qscore.updated
category:
| "mission"
| "service"
| "artifact"
| "usage"
| "qscore"
| "entitlement"
| "system";
occurredAt: string;
mission?: {
instanceId?: string;
missionId?: string;
stageId?: string;
};
subject?: {
kind: string;
id: string;
};
// example: { kind: "interview_session", id: sessionId }
correlation?: {
requestId?: string;
sessionId?: string;
resumeId?: string;
externalId?: string;
};
payload: Record<string, unknown>;
};
```
The important thing: **we store unknown events too.**
If an event type is new, we dont reject it. We save it, attach it to the user/mission if possible, and show it in debugging/timeline if useful.
---
# Postgres tables needed
Do not rely on actor state for durable history.
Add something like:
## `grow_events`
Append-only event inbox.
Fields:
- `id`
- `user_id`
- `mission_instance_id`
- `source`
- `type`
- `category`
- `subject_kind`
- `subject_id`
- `correlation_id`
- `payload`
- `occurred_at`
- `received_at`
- `processed_at`
- `processing_status`
- `error`
## `mission_service_sessions`
Tracks external service objects created for a mission.
Examples:
- interview session ID
- resume ID
- roleplay session ID
- qscore run ID
Fields:
- `id`
- `user_id`
- `mission_instance_id`
- `stage_id`
- `service_id`
- `external_type`
- `external_id`
- `status`
- `last_event_id`
- `last_checked_at`
- `created_at`
- `updated_at`
This table is crucial because the dashboard needs to know:
> “This missions interview stage corresponds to interview session `abc123`.”
## `mission_artifacts`
Could either reuse current snapshot artifacts or make durable table.
Examples:
- resume fit scan
- interview prep plan
- interview review
- readiness report
---
# Actor design
Do **not** put this all in `growActor`.
`growActor` is becoming chat/conversation/user home state. Missions should not depend on it.
## Best actor model
### 1. Mission actor per active mission
Already exists:
```txt
interviewToOfferMissionActor[userId, instanceId]
```
Extend it conceptually to support:
```ts
ingestEvent(event)
recomputeProjection()
scheduleExternalCheck()
getDashboardSnapshot()
```
The actor stores only bounded state:
- current stage
- progress
- latest known service session IDs
- latest scores
- artifact summaries
- next action
- last few events maybe
Raw events stay in Postgres.
### 2. Optional user analytics actor
A per-user analytics actor can exist later:
```txt
userAnalyticsActor[userId]
```
Its job:
- update user-level Q Score trend
- aggregate events across missions
- maintain dashboard analytics
- detect recommendations
But dont make it mandatory for v1. The mission actor + PG event store is enough.
### 3. Do not create one god event actor
Avoid:
```txt
globalEventProcessorActor
```
That becomes a bottleneck.
Better:
```txt
event ingest route → Postgres → mission actor for that mission/user
```
Rivet docs support actor queues and schedules, which are good primitives here. Use queues for ordered event processing and schedules for later status checks. The docs also note actor `noSleep` is deprecated in current docs, so we should avoid relying on permanent awake actors long-term, even though the project is pinned to `rivetkit ^2.2.1`.
---
# Event ingestion paths
We need multiple ingestion paths because not every service currently emits backend webhooks.
## 1. Backend gateway-generated events
Whenever the dashboard calls GrowQR backend gateway:
```txt
POST /services/interview/configure
POST /services/resume/resumes/:id/analyze
POST /services/interview/review/:sessionId
```
The backend should emit internal events like:
```txt
interview.configured
resume.analysis_requested
resume.analysis_completed
interview.review_completed
```
This is the easiest first layer.
## 2. Service webhook/event endpoint
Add a backend route:
```txt
POST /events/ingest
```
Services can call this when they complete things:
```txt
resume.ai_analysis_complete
interview.session_completed
interview.review_completed
roleplay.review_completed
```
This is ideal long term.
## 3. Redis stream bridge
Old services already use Redis streams for task responses.
We can add a backend consumer that listens to service response messages and converts them into Grow events.
But I would not make Redis the only source of truth. It should feed Postgres.
## 4. Polling/checker fallback
This is mandatory.
Some events will be missed. Some services currently only expose state through REST. Some live WebSocket events go straight to the browser.
So when a mission creates an interview session, store:
```txt
mission instance → interview session id
```
Then schedule checks:
```txt
check interview session/review in 30s
check again in 2m
check again in 5m
stop when completed/failed/expired
```
Actors are good for this because Rivet supports scheduled actions.
---
# How the mission updates automatically
Example: Interview-to-Offer.
## User buys mission
Backend creates event:
```txt
mission.purchased
```
Mission actor receives it:
- status: active
- stage: resume
- progress: 010%
- next action: upload/select resume
Dashboard shows:
> Next: Update your resume for this interview.
---
## User analyzes resume
Dashboard calls Resume service through backend.
Backend stores:
```txt
resume.analysis_requested
```
When result returns or poller finds result:
```txt
resume.ai_analysis_complete
```
Mission actor applies dynamic reducer:
- source = resume-service
- event contains resume analysis
- mission stage = resume
- mark resume stage done
- create artifact: Resume Fit Scan
- update progress
- next action: Start mock interview
No chat required.
---
## User starts interview
Backend gateway calls Interview service configure.
Backend stores:
```txt
interview.configured
```
Mission actor:
- links session ID to mission
- marks interview stage ready/in_progress
- next action: Start interview session
---
## User completes interview
Live WS sends `session.completed` to browser today.
But backend should know through one of:
1. service webhook,
2. backend polling review endpoint,
3. frontend callback to backend,
4. Redis bridge if session completion is emitted there.
Backend stores:
```txt
interview.session_completed
```
Mission actor:
- stage status: review pending
- next action: wait for review / view processing
---
## Review becomes available
Backend fetches:
```txt
GET /services/interview/review/:sessionId
```
If completed, store:
```txt
interview.review_completed
```
Mission actor:
- creates artifact: Mock Interview Review
- marks interview stage done
- extracts score/weaknesses
- publishes Q Score signals
- computes/requests final readiness
- updates dashboard
---
# Q Score integration
Q Score should be event-fed, not chat-fed.
Current old orchestrator extracts signals from service messages. We can reuse that idea but move it into backend event processing.
## Signal mapper should be dynamic-ish
Instead of a giant event registry, use a few generic extractors by category/source:
```txt
resume event → resume signal extractor
interview event → interview signal extractor
roleplay event → roleplay signal extractor
engagement/mission event → workflow signal extractor
```
This is not a mission registry. It is a small set of signal extractors.
Example interview review signals:
```txt
interview.completed
interview.overall_score
interview.language_score
interview.voice_score
interview.body_language_score
interview.filler_words
interview.technical_quality
```
Resume signals:
```txt
resume.uploaded
resume.ats_compatibility
resume.keyword_relevance
resume.grammar_clarity
resume.impact_statements
```
Mission signals:
```txt
mission.interview_to_offer.started
mission.interview_to_offer.resume_completed
mission.interview_to_offer.interview_completed
mission.interview_to_offer.completed
```
These are then sent to Q Score.
---
# Dashboard behavior
The mission dashboard should be driven by mission state, not chat messages.
## Active mission page
For Interview-to-Offer:
```txt
Interview-to-Offer Accelerator
Progress: 55%
Plan: $10/month
Usage:
- Interviews: 2 / 10
- Resume analyses: 1 / 3
Current step:
Mock Interview
Next action:
Start your 15-minute behavioral mock interview.
Completed:
✓ Mission purchased
✓ Resume selected
✓ Resume analyzed
✓ Resume fit scan generated
Artifacts:
- Resume Fit Scan
- Interview Prep Plan
- Mock Interview Review, pending
Readiness:
Baseline Q Score: 64
Current Q Score: 71
Delta: +7
```
## Stage cards
Each card has its own CTA:
Resume stage:
- Upload resume
- Select resume
- Analyze resume
- View fit scan
Interview stage:
- Configure mock interview
- Start interview
- View review
Final stage:
- Generate readiness report
- View final Q Score
No chat required.
---
# Chat/Grow Agents new role
Chat becomes a reader/writer of the same mission system.
It can:
- explain current mission status
- recommend next action
- call mission/service tools
- summarize artifacts
- answer “what should I do next?”
But if the user never opens chat, the mission still progresses.
So the Grow Agent should not own the mission. It should consume the mission projection.
---
# Subscription/usage tracking
For paid missions, usage should also be event-based.
Events:
```txt
entitlement.granted
usage.interview_session_created
usage.interview_session_completed
usage.resume_analysis_requested
usage.resume_analysis_completed
usage.limit_reached
subscription.renewed
subscription.cancelled
```
The gateway should enforce limits before creating expensive service sessions.
Example:
```txt
User clicks Start Interview
Backend checks entitlement
If allowed, create interview session
Insert usage event
Increment monthly usage
```
Do not rely on frontend hiding buttons.
---
# What I would build first
## Phase 1 — Mission event backbone
No new product logic yet. Just make events durable.
- `grow_events`
- `mission_service_sessions`
- `/events/ingest`
- backend helper: `recordGrowEvent()`
- event forwarding to mission actor
- mission actor `ingestEvent()`
## Phase 2 — Backend gateway emits mission events
Whenever dashboard uses service routes, backend records events.
Examples:
- interview configured
- interview review fetched
- resume analyzed
- resume version saved
## Phase 3 — Mission actor becomes projection reducer
Add generic dynamic handling:
- store unknown events
- update timeline
- if event matches current stage service, update stage
- attach artifacts if payload has review/analysis/export
- update next action
## Phase 4 — Polling fallback
For linked external sessions:
- poll interview review until completed
- poll roleplay review until completed
- poll resume analysis state if needed
## Phase 5 — Q Score bridge
Convert service events into Q Score signals and publish them.
## Phase 6 — Dashboard reads projection
Dashboard should not guess. It reads:
```txt
GET /missions/active/:instanceId
```
and renders:
- stages
- events
- artifacts
- next action
- usage
- score trend
---
# Key recommendation
Do not create another large service/action registry.
Use this instead:
1. **Feature registry** remains the product source of truth.
2. **Mission definitions** define stages and included services.
3. **Events are dynamic** and stored raw.
4. **Small generic reducers** interpret categories/sources.
5. **Unknown events are accepted, stored, and visible.**
6. **Actors project events into live mission state.**
7. **Postgres remains authoritative.**
That gives you the cohesive, event-driven mission system youre describing without recreating the old orchestrator registry.

View File

@@ -0,0 +1,456 @@
# Frontend V2 Service UI Port Plan
Date: 2026-06-01
## Purpose
This document is the handoff/merge plan for porting only the useful service UIs from `growqr-app/frontend` into `growqr-next-frontend` under `/v2`, without pulling unrelated legacy app changes.
The backend now has workflow orchestration and service facades for interview, roleplay, resume, and qscore. The next frontend work should expose polished service pages that workflows can redirect users into when a human/live sub-agent step is required.
## Source and target repos
Source UI reference:
```txt
/Users/puter/Workspace/growqr/growqr-app/frontend
```
Target frontend:
```txt
/Users/puter/Workspace/growqr/growqr-next-frontend
```
Target mount namespace:
```txt
/v2/services/*
```
## Important constraint
Do **not** port all of `growqr-app/frontend`.
Only port the service surfaces needed by workflows:
- Interview service UI
- Roleplay service UI
- Resume service UI
- Shared analysis/live-session widgets used by the above
Avoid unrelated areas:
- Billing / Razorpay
- Cover letters, unless explicitly needed later
- Settings pages
- Onboarding flows
- Old dashboard shell
- Social branding pages
- Legacy app navigation/sidebar
## Desired routes in `growqr-next-frontend`
Create these pages:
```txt
src/app/v2/services/interview/page.tsx
src/app/v2/services/interview/setup/page.tsx
src/app/v2/services/interview/preview/page.tsx
src/app/v2/services/interview/feedback/page.tsx
src/app/v2/services/roleplay/page.tsx
src/app/v2/services/roleplay/setup/page.tsx
src/app/v2/services/roleplay/builder/page.tsx
src/app/v2/services/roleplay/feedback/page.tsx
src/app/v2/services/resume/page.tsx
src/app/v2/services/resume/[id]/page.tsx
```
Workflow redirects should eventually point to these routes, for example:
```txt
interview module → /v2/services/interview/setup?workflowRunId=...
roleplay module → /v2/services/roleplay/setup?workflowRunId=...
resume module → /v2/services/resume?workflowRunId=...
```
## Interview UI to port
Source pages:
```txt
growqr-app/frontend/src/app/(dashboard)/upskilling/interview/page.tsx
growqr-app/frontend/src/app/(dashboard)/upskilling/interview/setup/page.tsx
growqr-app/frontend/src/app/(dashboard)/upskilling/interview/preview/page.tsx
growqr-app/frontend/src/app/(dashboard)/upskilling/interview/feedback/page.tsx
```
Source components:
```txt
growqr-app/frontend/src/components/interview/InterviewLaunchOverlay.tsx
growqr-app/frontend/src/components/interview/EquipmentCheckModal.tsx
growqr-app/frontend/src/components/interview/LiveAvatarVideo.tsx
growqr-app/frontend/src/components/interview/CoachingBanner.tsx
growqr-app/frontend/src/components/interview/BuilderTipsCarousel.tsx
growqr-app/frontend/src/components/interview/InterviewTipsCarousel.tsx
growqr-app/frontend/src/components/interview/YourResultsSection.tsx
growqr-app/frontend/src/components/feedback/FeedbackDashboard.tsx
growqr-app/frontend/src/components/feedback/PresenceSection.tsx
growqr-app/frontend/src/components/feedback/VideoAnalysisSection.tsx
```
Supporting hooks/libs:
```txt
growqr-app/frontend/src/hooks/useInterviewMedia.ts
growqr-app/frontend/src/hooks/useInterviewSession.ts
growqr-app/frontend/src/hooks/useInterviewReview.ts
growqr-app/frontend/src/hooks/useSessionRecorder.ts
growqr-app/frontend/src/hooks/useFaceFeedback.ts
growqr-app/frontend/src/hooks/useLighting.ts
growqr-app/frontend/src/hooks/useCoachingHints.ts
growqr-app/frontend/src/hooks/usePresenceAggregator.ts
growqr-app/frontend/src/lib/interview/types.ts
growqr-app/frontend/src/lib/interview/lastRoute.ts
growqr-app/frontend/src/lib/api/interview.ts
growqr-app/frontend/src/lib/coaching/*
```
What this gives us:
- Interview landing / role selection
- Setup screen with persona, duration, audio/video mode
- Generated interview plan preview
- Live Avatar launch overlay
- Equipment check
- Live mic/camera session UI
- Transcript handling
- Post-interview analysis report
- Presence/video analysis sections
## Roleplay UI to port
Source pages:
```txt
growqr-app/frontend/src/app/(dashboard)/upskilling/roleplay/page.tsx
growqr-app/frontend/src/app/(dashboard)/upskilling/roleplay/setup/page.tsx
growqr-app/frontend/src/app/(dashboard)/upskilling/roleplay/builder/page.tsx
growqr-app/frontend/src/app/(dashboard)/upskilling/roleplay/feedback/page.tsx
```
Source components:
```txt
growqr-app/frontend/src/components/roleplay/RoleplayLaunchOverlay.tsx
growqr-app/frontend/src/components/roleplay/LiveAvatarVideo.tsx
growqr-app/frontend/src/components/roleplay/RoleplayFeedbackDashboard.tsx
```
Shared components reused from interview/feedback:
```txt
growqr-app/frontend/src/components/interview/EquipmentCheckModal.tsx
growqr-app/frontend/src/components/interview/CoachingBanner.tsx
growqr-app/frontend/src/components/feedback/PresenceSection.tsx
growqr-app/frontend/src/components/feedback/VideoAnalysisSection.tsx
```
Supporting hooks/libs:
```txt
growqr-app/frontend/src/hooks/useRoleplaySession.ts
growqr-app/frontend/src/hooks/useRoleplayReview.ts
growqr-app/frontend/src/lib/roleplay/types.ts
growqr-app/frontend/src/lib/roleplay/scenarios.ts
growqr-app/frontend/src/lib/roleplay/lastRoute.ts
growqr-app/frontend/src/lib/api/roleplay.ts
```
What this gives us:
- Roleplay scenario picker
- Custom scenario builder
- Generated roleplay brief preview
- Live Avatar roleplay overlay
- Post-roleplay feedback/analysis report
## Resume UI to port
Source pages:
```txt
growqr-app/frontend/src/app/(dashboard)/opportunities/resume/page.tsx
growqr-app/frontend/src/app/(dashboard)/opportunities/resume/[id]/page.tsx
```
Source components:
```txt
growqr-app/frontend/src/components/resume/ResumeList.tsx
growqr-app/frontend/src/components/resume/ResumeCard.tsx
growqr-app/frontend/src/components/resume/ResumeUpload.tsx
growqr-app/frontend/src/components/resume/ResumePreviewModal.tsx
growqr-app/frontend/src/components/resume/ResumeEditor/ResumeEditor.tsx
growqr-app/frontend/src/components/resume/ResumeEditor/ResumeStrengthBar.tsx
growqr-app/frontend/src/components/resume/ResumeEditor/AccordionPanel.tsx
growqr-app/frontend/src/components/resume/ResumeEditor/components/*
growqr-app/frontend/src/components/resume/ResumeEditor/sections/*
growqr-app/frontend/src/components/resume/ResumeEditor/tabs/AICopilot.tsx
growqr-app/frontend/src/components/resume/ResumeEditor/tabs/DesignTab.tsx
growqr-app/frontend/src/components/resume/AIAnalysis/*
```
Supporting libs/types:
```txt
growqr-app/frontend/src/lib/api/resumes.ts
growqr-app/frontend/src/types/resume.ts
```
Important resume adaptation:
The source resume hub includes a cover-letter tab. For this phase, remove the cover-letter tab and keep resume-only UI.
## API integration strategy
Prefer our backend service facades through the existing Next proxy:
```txt
/api/growqr/services/interview/*
/api/growqr/services/roleplay/*
/api/growqr/services/resume/*
```
Backend facade examples already present:
```txt
GET /services/catalog
GET /services/:service/health
POST /services/interview/configure
POST /services/interview/preview
POST /services/interview/questions
POST /services/interview/approve
GET /services/interview/review/:sessionId
GET /services/interview/leaderboard
GET /services/interview/artifacts/:sessionId/:artifactType
POST /services/interview/sessions/:sessionId/video/upload-url
POST /services/interview/sessions/:sessionId/video/uploaded
POST /services/roleplay/configure
POST /services/roleplay/preview
POST /services/roleplay/questions
POST /services/roleplay/approve
GET /services/roleplay/review/:sessionId
GET /services/roleplay/leaderboard
GET /services/roleplay/artifacts/:sessionId/:artifactType
POST /services/roleplay/sessions/:sessionId/video/upload-url
POST /services/roleplay/sessions/:sessionId/video/uploaded
GET /services/resume/templates
GET /services/resume/resumes
POST /services/resume/resumes
GET /services/resume/resumes/:resumeId
PUT /services/resume/resumes/:resumeId
POST /services/resume/resumes/:resumeId/analyze
GET /services/resume/resumes/:resumeId/suggestions
POST /services/resume/ai/copilot
POST /services/resume/ai/optimize-summary
POST /services/resume/ai/optimize-experience
POST /services/resume/ai/suggest-skills
POST /services/resume/ai/generate-summary
GET /services/resume/resumes/:resumeId/versions
POST /services/resume/resumes/:resumeId/versions
GET /services/resume/resumes/:resumeId/preview
```
Recommended target API clients:
```txt
growqr-next-frontend/src/lib/services/interview.ts
growqr-next-frontend/src/lib/services/roleplay.ts
growqr-next-frontend/src/lib/services/resume.ts
```
These should call `/api/growqr/services/...`, not raw service URLs, wherever possible.
## WebSocket caveat
The existing Next route proxy at:
```txt
growqr-next-frontend/src/app/api/growqr/[...path]/route.ts
```
is HTTP-only and does not proxy WebSockets.
Live interview/roleplay session overlays still need direct service WS URLs unless we add a backend WS gateway later:
```txt
NEXT_PUBLIC_INTERVIEW_WS_URL
NEXT_PUBLIC_ROLEPLAY_WS_URL
```
The old source defaults were:
```txt
ws://localhost:8007/api/v1
ws://localhost:8008/api/v1
```
Keep this in mind when validating the live avatar/audio session flow.
## Dependencies likely needed in `growqr-next-frontend`
Source UI uses these packages not guaranteed in target:
```txt
@mediapipe/tasks-vision
livekit-client
html2canvas
jspdf
react-markdown
```
Source imports `motion/react`. Target already has `framer-motion`; either:
1. add `motion`, or
2. rewrite imports from `motion/react` to `framer-motion`.
Prefer option 2 if low-friction, to reduce dependency drift.
## Assets to copy
```txt
growqr-app/frontend/public/mediapipe/*
growqr-app/frontend/public/assets/images/personas/john.jpg
growqr-app/frontend/public/assets/images/company-logos/*
```
The MediaPipe files are required by the face-feedback/presence coaching hooks.
## CSS utilities to port
From:
```txt
growqr-app/frontend/src/app/globals.css
```
Port only the service UI utilities/tokens needed by copied components:
```css
--color-brand-orange
--color-brand-orangeLight
--color-brand-orangeMuted
.scrollbar-orange
.glass
.glass-strong
.gradient-mesh
.gradient-hero
.gradient-orange
.text-gradient
.glow-primary
.glow-orange
.animate-float
.animate-pulse-glow
```
Also verify Tailwind theme exposes `brand-orange` if copied components use classes like:
```txt
text-brand-orange
bg-brand-orange
border-brand-orange
```
## Layout adaptation
Do not port the old `growqr-app` dashboard shell.
Use target app's existing V2 shell:
```txt
growqr-next-frontend/src/app/v2/layout.tsx
growqr-next-frontend/src/components/layout-v2/DashboardLayout.tsx
```
When copying source pages, remove imports of:
```txt
@/components/layout/DashboardLayout
```
because `/v2/layout.tsx` already wraps children.
If a copied page needs full-width/no-padding behavior for live overlays or feedback reports, adapt locally inside `/v2/services/...` rather than replacing the global V2 layout.
## Known import cleanup to avoid pulling too much
Some source components import unrelated pieces. Replace or stub these:
```txt
src/components/dashboard-v2/cards/QuotientDistributionCard.tsx
src/components/leaderboard/Leaderboard.tsx
```
Options:
1. Port tiny versions if needed by feedback sections.
2. Replace with simple local cards.
3. Temporarily remove leaderboard sections from service pages if they block build.
For resume, avoid imports from:
```txt
src/components/coverLetter/*
src/components/billing/*
src/components/onboarding/*
```
## Suggested implementation order
1. Add service API clients in target.
2. Port shared CSS tokens/utilities and assets.
3. Port interview types/hooks/components/pages.
4. Build and fix interview only.
5. Port roleplay types/hooks/components/pages.
6. Build and fix roleplay only.
7. Port resume types/API/components/pages, resume-only.
8. Build and fix resume only.
9. Update workflow UI redirects/buttons to point to `/v2/services/...`.
10. Run final validation.
## Validation commands
From target frontend:
```bash
cd /Users/puter/Workspace/growqr/growqr-next-frontend
bunx tsc --noEmit
bun run build
```
Known note: lint may have unrelated legacy/pre-existing failures. Do not treat unrelated lint noise as the merge blocker unless the new service UI introduces it.
## Merge checklist
- [ ] New service pages live under `/v2/services/*` only.
- [ ] No unrelated billing/settings/onboarding/social-branding UI copied.
- [ ] Interview setup → preview → live overlay → feedback compiles.
- [ ] Roleplay setup/builder → live overlay → feedback compiles.
- [ ] Resume list/upload/editor/analysis compiles.
- [ ] All service HTTP calls go through `/api/growqr/services/...` where possible.
- [ ] WebSocket env vars documented for live interview/roleplay sessions.
- [ ] Workflows can redirect to the new service routes.
- [ ] `bunx tsc --noEmit` passes.
- [ ] `bun run build` passes.

View File

@@ -0,0 +1,553 @@
# GrowQR Backend Launch Gap Plan
This document only lists the **differences between the current backend and the target sellable-workflow platform**. It is written so a backend agent can work independently from the frontend/UI agent.
Target assumption: workflows are sellable products; services are reusable capability engines; OpenCode is the per-user agentic execution workspace; Gitea is version-backed career memory; Rivet provides durable actor/workflow orchestration.
---
## 1. Current backend state observed
Relevant backend files inspected:
- `growqr-backend/src/index.ts`
- `growqr-backend/src/config.ts`
- `growqr-backend/src/routes/workflows.ts`
- `growqr-backend/src/routes/chat.ts`
- `growqr-backend/src/routes/agents.ts`
- `growqr-backend/src/routes/opencode.ts`
- `growqr-backend/src/actors/user-actor.ts`
- `growqr-backend/src/db/schema.ts`
- `growqr-backend/src/docker/manager.ts`
- `growqr-backend/src/lib/opencode.ts`
- `growqr-backend/src/lib/prompt-loader.ts`
- `growqr-backend/src/services/service-agents.ts`
- `growqr-backend/prompts/system.txt`
- `growqr-backend/agents/*.md`
### Already aligned / do not rewrite now
- Clerk-authenticated backend routes exist.
- Central Gitea + per-user repo model exists.
- Per-user OpenCode container lifecycle exists.
- Custom OpenCode image support exists.
- OpenCode workspace cloning/syncing exists.
- Prompt/agent markdown loading exists.
- Password is stripped from public stack responses.
- User actor exists and can manage chat, workflow state, service calls, Gitea memory, and stack provisioning.
- Basic microservice adapters exist for resume, interview, roleplay, and Q Score.
---
## 2. Critical backend gaps
### Gap A — Workflow API is hardcoded to `job-application`
Current evidence:
- `routes/workflows.ts` exposes only:
- `GET /workflows/job-application`
- `POST /workflows/job-application`
- `POST /workflows/job-application/pause`
- `POST /workflows/job-application/resume`
- `POST /workflows/job-application/agents/:moduleId/run`
- `POST /workflows/job-application/agents/:moduleId/score`
- `user-actor.ts` sets IDs like `job-application:${userId}`.
- `prompt-loader.ts` has `jobApplicationModuleIds()` hardcoded to `resume`, `job-search`, `job-apply`, `sara`, `emily`, `qscore`.
Target difference:
- Backend owns a real workflow product catalog.
- Routes are parameterized by workflow ID.
- The current route surface can stay as compatibility aliases, but the canonical API should be generic.
Required change:
Add backend workflow registry:
```txt
src/workflows/
types.ts
registry.ts
definitions/
interview-to-offer.ts
career-transition.ts
salary-negotiation-war-room.ts
promotion-readiness.ts
personal-brand-opportunity-engine.ts
first-job-launchpad.ts
```
Add routes:
```txt
GET /workflows
GET /workflows/:workflowId
POST /workflows/:workflowId/runs
GET /workflows/:workflowId/runs/current
GET /workflow-runs/:runId
POST /workflow-runs/:runId/pause
POST /workflow-runs/:runId/resume
POST /workflow-runs/:runId/modules/:moduleId/run
POST /workflow-runs/:runId/approvals/:approvalId
```
Keep temporary aliases:
```txt
/workflows/job-application → /workflows/interview-to-offer or /workflows/job-fit-apply-autopilot
```
---
### Gap B — Workflow state is only actor memory, not a production run model
Current evidence:
- `db/schema.ts` has users, stacks, actors, repos, sessions, events.
- No `workflow_definitions`, `workflow_runs`, `workflow_steps`, `workflow_artifacts`, `workflow_approvals`, or `qscore_snapshots` tables exist.
- `user-actor.ts` keeps one workflow state in actor state: `workflowId`, `workflowStatus`, `workflowGoal`, `modules`, `timeline`.
Target difference:
- Workflow runs should be queryable, auditable, resumable, and visible even if the actor is unavailable.
- Actor state can stay as the fast durable executor, but Postgres needs product/run records.
Required change:
Add minimal launch tables:
```txt
workflow_runs
id
user_id
workflow_id
workflow_version
status
goal
input jsonb
current_step_id
progress_percent
qscore_before jsonb
qscore_after jsonb
created_at
updated_at
completed_at
workflow_run_modules
id
run_id
module_id
title
status
service
output_summary
output jsonb
error
started_at
completed_at
workflow_artifacts
id
run_id
module_id
type
title
repo_path
public_url
metadata jsonb
created_at
workflow_events
id
run_id
user_id
type
payload jsonb
created_at
```
For tomorrow, these can be simple Drizzle tables plus migration, not a full enterprise workflow engine.
---
### Gap C — No backend-owned sellable workflow definitions
Current evidence:
- Agent markdown files exist, but workflow products do not.
- Workflow metadata such as title, promise, pricing, outputs, visual theme, required inputs, score dimensions, and artifact specs is absent.
- Frontend currently fills this gap with hardcoded workflow cards.
Target difference:
- Backend should return workflow products directly to frontend.
Required launch definitions:
1. `interview-to-offer`
2. `career-transition`
3. `salary-negotiation-war-room`
4. `promotion-readiness`
5. `personal-brand-opportunity-engine`
6. optional: `first-job-launchpad`
Each definition should include:
```ts
type WorkflowDefinition = {
id: string;
version: string;
title: string;
shortTitle: string;
promise: string;
segment: string[];
urgency: "low" | "medium" | "high";
estimatedDuration: string;
priceTier: "free" | "starter" | "premium";
visual: {
icon: string;
color: string;
mascotAgentIds: string[];
};
requiredInputs: Array<{ id: string; label: string; type: string; required: boolean }>;
modules: WorkflowModuleDefinition[];
outputs: ArtifactDefinition[];
qscoreDimensions: string[];
approvalGates: ApprovalDefinition[];
}
```
---
### Gap D — Workflow modules can still complete as local placeholders
Current evidence:
- In `user-actor.ts`, modules with no `service` return summaries like:
- `completed a local workflow step for ...`
- `completed a local workflow step.`
- `service-agents.ts` returns `status: "local"` for agents without a service.
- `job-search` and `job-apply` currently act as local modules.
Target difference:
- No backend route should report real completion unless one of these happened:
1. microservice executed,
2. OpenCode executed and produced an artifact,
3. user/human approval happened,
4. module is explicitly marked `blocked` / `manual_required` / `coming_soon`.
Required change:
- Replace local success with explicit statuses:
- `blocked_service_unavailable`
- `manual_required`
- `waiting_for_input`
- `opencode_required`
- `coming_soon`
- For launch workflows, every module must either call a real service, call OpenCode, or return a non-success blocked/manual status.
---
### Gap E — OpenCode exists but is not yet the workflow execution engine
Current evidence:
- `lib/opencode.ts` can create sessions and send messages.
- `routes/opencode.ts` exposes session creation/message proxy.
- `docker/manager.ts` provisions per-user OpenCode containers and syncs workspace to Git.
- `user-actor.ts` workflow modules call `runServiceAgentProbe()` directly and do not use OpenCode for artifact generation.
Target difference:
- OpenCode should execute prompt-backed career artifact work when a module needs generated files or memory writes.
Required change:
Create a backend adapter:
```txt
src/workflows/executors/opencode-executor.ts
```
Responsibilities:
- ensure/provision stack,
- create OpenCode session per workflow module,
- send workflow-specific prompt,
- require structured JSON or markdown outputs,
- write artifacts under `/workspace/artifacts/...`,
- sync workspace to Git,
- return artifact metadata to `workflow_artifacts`.
Launch use cases for OpenCode:
- interview prep plan,
- likely questions,
- behavioral story bank,
- negotiation script,
- promotion evidence packet,
- LinkedIn/profile rewrite draft,
- weekly brand content plan.
---
### Gap F — Prompt system is global, not workflow/product optimized
Current evidence:
- `prompts/system.txt` is one global Grow Agent prompt.
- Agent markdown files load into `{{MODULE_DESCRIPTIONS}}`.
- `user-actor.ts` manually defines tools and a special `start_interview_to_offer` path.
- No workflow-specific prompt packs, output schemas, or eval checks exist.
Target difference:
- Each sellable workflow should have prompt packs and artifact contracts.
Required change:
Add workflow prompt files:
```txt
prompts/workflows/
interview-to-offer/
orchestrator.md
resume-analysis.md
interview-plan.md
story-bank.md
final-readiness-report.md
career-transition/
salary-negotiation-war-room/
promotion-readiness/
personal-brand-opportunity-engine/
```
Each module prompt should specify:
- role,
- inputs,
- user tone,
- output artifact path,
- required sections,
- JSON metadata contract,
- Q Score dimensions affected,
- what must be saved to memory.
For prompt optimization tomorrow:
- Add a small local prompt smoke test that verifies each workflow prompt produces required sections/JSON keys.
- Version prompts with `PROMPT_VERSION`.
- Store prompt version on `workflow_runs` and artifacts.
---
### Gap G — Chat route duplicates orchestration and infers workflow state
Current evidence:
- `routes/chat.ts` first tries Rivet actor, then falls back to direct LLM/tool dispatch.
- The fallback has its own tool list, service calls, hardcoded localhost demo URLs, and `inferWorkflowStep()` heuristic.
- `user-actor.ts` also has tool dispatch and workflow logic.
Target difference:
- Backend chat should not maintain a separate workflow engine.
- Direct fallback may answer conversationally, but should not fabricate workflow state or duplicate module execution.
Required change:
- Make `userActor` / workflow service the only workflow mutation path.
- In `routes/chat.ts`, fallback options should be limited to:
- simple LLM response with no workflow state, or
- call backend workflow service APIs, not duplicate logic.
- Remove `inferWorkflowStep()` as product state source.
- Replace session URL construction with service-provided/public configured URLs.
---
### Gap H — Session URLs are hardcoded to localhost
Current evidence:
- `user-actor.ts` returns session URLs using `http://localhost:8007` and `http://localhost:8008`.
- `routes/chat.ts` does the same.
Target difference:
- Backend should return service URLs configured for the current environment.
- Frontend should never construct or guess microservice URLs.
Required change:
- Add config values:
- `INTERVIEW_PUBLIC_URL`
- `ROLEPLAY_PUBLIC_URL`
- `RESUME_PUBLIC_URL` if needed
- Service adapters should return canonical `sessionUrl` fields.
- Actor/chat responses should pass through those URLs.
---
### Gap I — Q Score is not yet a durable platform layer
Current evidence:
- `service-agents.ts` uses static signal examples and can return an estimated Q Score fallback.
- No durable `qscore_snapshots` table exists in backend.
- Frontend QX page is mostly static.
Target difference:
- Every workflow should read baseline Q Score, update signals, and save before/after snapshots.
Required change:
- Add `qscore_snapshots` or store snapshots on `workflow_runs` for launch.
- Add `qscore_signal_events` later if needed.
- Workflow module results should include `qscoreDelta` metadata when relevant.
- Do not claim score improvement unless Q Score service or explicit estimate contract returns it.
---
### Gap J — No entitlement/billing gate around sellable workflows
Current evidence:
- No workflow SKU/entitlement model in schema.
- Routes allow authenticated users to start workflows without plan checks.
Target difference:
- Sellable workflows need at least a launch-ready entitlement boundary.
Required launch change:
Add simple fields to workflow definition:
```txt
priceTier
sku
isPurchasable
isFreePreview
```
Add minimal backend checks:
- Free workflows can start.
- Paid workflows return `402/payment_required` or `locked` response if no entitlement.
- For tomorrow, this can be stubbed with env/config allowlist while payment is wired later.
---
## 3. Big backend phases
### Phase 1 — Tomorrow sellable workflow control plane
Goal: make backend safe to sell real workflows even if some specialized services are still evolving.
Must build/change:
1. Workflow registry with launch workflow definitions.
2. `GET /workflows` and generic workflow detail endpoint.
3. Generic workflow run routes.
4. Minimal workflow run persistence tables.
5. User actor updated to accept `workflowId` and use registry modules.
6. Replace local fake module success with blocked/manual/OpenCode statuses.
7. Add OpenCode executor for artifact-producing modules.
8. Add workflow-specific prompts and artifact contracts.
9. Return service/session URLs from config or service response, not localhost constants.
10. Keep `job-application` route aliases temporarily for old frontend calls.
Definition of done:
- Backend returns a real catalog of sellable workflows.
- A user can start `interview-to-offer` and get a durable run ID.
- Modules either execute a real service/OpenCode task or show an honest blocked/manual status.
- Generated artifacts are written to user repo and recorded in backend.
- Frontend can render run state without hardcoded workflow knowledge.
---
### Phase 2 — Production-grade orchestration and memory
Goal: make workflow runs reliable, resumable, and supportable.
Must build/change:
1. Move long-running module execution toward Rivet workflow steps or one actor/action per run.
2. Add retry policy and idempotency keys per module.
3. Add approval gates:
- user input required,
- review artifact,
- approve next step,
- human escalation.
4. Add event stream/poll endpoint for frontend progress.
5. Add artifact browser API:
- list artifacts,
- read artifact metadata,
- get repo path/content.
6. Add prompt/output validation:
- required files produced,
- required JSON keys,
- no empty success.
7. Add run history and completed workflow summaries.
Definition of done:
- A workflow can survive backend restarts and actor restarts.
- Support can inspect run events/artifacts.
- Users can resume an interrupted workflow.
---
### Phase 3 — Scale, entitlements, and product ops
Goal: make the backend ready for paid launch scale and operational control.
Must build/change:
1. Real billing/entitlement integration.
2. Workflow version rollout controls.
3. Prompt version rollout controls.
4. Admin observability:
- failed runs,
- blocked services,
- OpenCode container health,
- Gitea sync health.
5. Service capability registry:
- which microservices are enabled,
- health,
- supported operations,
- public session URL patterns.
6. Analytics events:
- workflow viewed,
- run started,
- module started/completed/failed,
- artifact generated,
- score updated.
Definition of done:
- Workflows are measurable, billable, versioned, and operationally safe.
---
## 4. Backend agent handoff checklist
Work in this order:
1. Add `src/workflows/types.ts` and `src/workflows/registry.ts`.
2. Define the 5 launch workflow products.
3. Add `GET /workflows` and `GET /workflows/:workflowId`.
4. Add minimal workflow run tables and migration.
5. Generalize `routes/workflows.ts` while keeping `job-application` aliases.
6. Update `user-actor.ts` so `startWorkflow({ workflowId, goal, input })` uses registry modules.
7. Replace local success fallback with honest non-success statuses.
8. Add OpenCode workflow executor for artifact modules.
9. Add workflow prompt packs and output contracts.
10. Remove localhost session URL construction from actor/chat responses.
11. Simplify `routes/chat.ts` so workflow mutation only goes through actor/workflow service.
Do not spend this pass on rewriting specialized microservices. Treat them as capability adapters behind stable workflow module contracts.

View File

@@ -0,0 +1,389 @@
# GrowQR Frontend v2 Launch Gap Plan
This document only lists the **differences between the current v2 frontend and the target sellable-workflow product**. It is written so a frontend/UI agent can work independently from the backend agent.
Target assumption: backend owns workflow definitions, runs, score data, artifacts, agent availability, entitlements, and session URLs. The frontend renders that state in a playful, visual, low-reading experience.
---
## 1. Current frontend state observed
Relevant v2 files inspected:
- `growqr-next-frontend/src/app/v2/page.tsx`
- `growqr-next-frontend/src/app/v2/workflows/page.tsx`
- `growqr-next-frontend/src/app/v2/chat/page.tsx`
- `growqr-next-frontend/src/app/v2/dashboard/page.tsx`
- `growqr-next-frontend/src/app/v2/agents/page.tsx`
- `growqr-next-frontend/src/app/v2/qx-score/page.tsx`
- `growqr-next-frontend/src/app/v2/pathways/page.tsx`
- `growqr-next-frontend/src/app/v2/marketplace/page.tsx`
- `growqr-next-frontend/src/app/v2/qvue/page.tsx`
- `growqr-next-frontend/src/components/home-v2/GrowChat.tsx`
- `growqr-next-frontend/src/components/home-v2/WorkflowDiscovery.tsx`
- `growqr-next-frontend/src/components/home-v2/WorkflowProgress.tsx`
- `growqr-next-frontend/src/components/home-v2/ChatInterface.tsx`
- `growqr-next-frontend/src/app/api/growqr/[...path]/route.ts`
### Already useful
- `/v2/workflows/page.tsx` is mostly backend-only and no longer shows example workflow progress.
- `/v2/chat/page.tsx` uses `GrowChat`, which calls the backend/actor path and avoids local fabricated final answers when the backend fails.
- `/api/growqr/[...path]/route.ts` exists as a Clerk-authenticated proxy to the backend.
- The visual direction is correct: agent avatars, large cards, simple labels, progress bars, and playful dashboard shell.
### Additional UI reference checked
Source: `docs/UI design Mockup Draft.pptx`.
The mockup makes the frontend direction more explicit than the original gap plan did: GrowQR should feel like a **visual career operating system**, not a text dashboard. Keep the existing GrowQR branding/colors, but change the UI/UX toward:
- **iPhone/App Library style grouping**: Home should group many capabilities into simple visual folders/widgets instead of long menus or dense dashboards. Example groups from the mockup: Suggestions, Workflows, Pathways, Daily Rewards, Social, Productivity.
- **Widget-first Home**: Home is not a report page. It should show daily actions, active workflows/opportunities, Q Score, rewards, and small group summaries as tappable widgets that drill down.
- **Low-reading UX**: for Tier-2/Tier-3 India, students, freshers, and seekers, most information should be absorbed through icons, agent avatars, cards, progress maps, charts, badges, animations, and pictorial states. English copy should be short: one clear line + one CTA.
- **TalkwithME as a primary mode**: a video/avatar conversational surface should support voice and text, suggested prompt chips, history, and personalized guidance from the user journey. It should compare progress with peers/industry standards only when backend data is real.
- **Workflows as agent squads**: workflow cards should visually show the group of agents working together toward one outcome in a finite period of time. Active workflows need tabs, summary, action buttons, agent areas, artifact previews, charts, and feedback controls.
- **Available vs Active mental model**: Workflows, Opportunities/Agents, and other catalog surfaces should separate what can be bought/started from what is already running.
- **Opportunities/Agents are one-off tasks**: workflows are outcome bundles; opportunities/agents are cheaper single-purpose actions such as Resume, Social Branding, Interview, Role Play, Assessments, Jobs, Courses, Mentorships. Pathway is a one-time report/agent, while daily guidance belongs in workflows.
- **Apple-inspired simplicity**: complex product breadth should be hidden behind grouped widgets, folders, bottom/side navigation, and progressive disclosure. Maximum capability, minimum visible complexity.
---
## 2. Critical product gaps
### Gap A — Workflow discovery is still frontend-owned
Current evidence:
- `WorkflowDiscovery.tsx` has a hardcoded `WORKFLOWS` object.
- The cards include IDs like `job-preparation`, `interview-practice`, `resume-boost`, `career-switch`, and `job-search` that do not all exist as backend workflow products.
- `/v2/workflows/page.tsx` only knows `/workflows/job-application`.
Target difference:
- Frontend should call `GET /workflows` and render backend-owned workflow products.
- Cards should represent sellable launch SKUs such as:
- `interview-to-offer`
- `career-transition`
- `salary-negotiation-war-room`
- `promotion-readiness`
- `personal-brand-opportunity-engine`
- optionally `first-job-launchpad`
- Frontend may own presentation, but not product definition.
Required change:
- Replace `WORKFLOWS` in `WorkflowDiscovery.tsx` with backend catalog data.
- Update `/v2/workflows/page.tsx` from one hardcoded job-application screen to:
- catalog grid,
- workflow detail drawer/page,
- active run view,
- module/artifact/status cards.
---
### Gap B — Multiple v2 pages still show static/demo business data
Current evidence:
- `dashboard/page.tsx` hardcodes QX score `76`, applications, interviews, skills, milestones, weekly activity, and agent stats.
- `agents/page.tsx` hardcodes agents, metrics, and “Active” state.
- `qx-score/page.tsx` hardcodes score `74` and visual areas.
- `pathways/page.tsx` hardcodes pathway programs and progress.
- `marketplace/page.tsx` hardcodes experts, ratings, availability, and counts.
- `qvue/page.tsx` hardcodes videos, views, ratings, and categories.
- `DashboardSections.tsx`, `AgentExecution.tsx`, and `CareerCoPilot.tsx` also contain static/demo surfaces.
Target difference:
- For launch, every visible claim should be one of:
1. real backend data,
2. a real backend catalog item,
3. an empty/coming-soon locked state,
4. a marketing card that clearly starts a real backend workflow.
Required change:
- Convert pages into real-data shells:
- Dashboard: active workflow runs, latest artifacts, latest Q Score snapshot, next recommended workflow.
- Agents: backend agent catalog + availability/status only.
- QX Score: backend Q Score summary; if unavailable, show “Run Q Score” CTA, not fake score.
- Pathways/QVue/Marketplace: either hide from launch nav or convert to locked/coming-soon backed by backend catalog.
---
### Gap C — Chat has duplicated and conflicting implementations
Current evidence:
- `/v2/chat/page.tsx` uses `GrowChat`.
- `HomeV2Client.tsx` and `marketplace/page.tsx` can use `ChatInterface`.
- `ChatInterface.tsx` contains `processResponse()` with local fabricated suggestions and action cards.
- `ChatInterface.tsx` still references old `growAgent` actor naming.
- `GrowChat.tsx` is closer to the desired path, but still contains hardcoded suggestions, hardcoded agent metadata, and backend/session assumptions.
Target difference:
- One production chat surface for v2.
- Chat should only display:
- assistant text from backend,
- backend sessions,
- backend workflow suggestions,
- backend workflow run state,
- backend artifacts.
Required change:
- Make `GrowChat` the only v2 chat component for launch.
- Stop using `ChatInterface` in v2 launch surfaces, or refactor it to delegate to `GrowChat` and delete local `processResponse()`.
- Move suggestions from frontend constants to backend responses/catalog.
---
### Gap D — Initial query behavior is still fragile
Current evidence:
- In `GrowChat.tsx`, welcome message is inserted on mount.
- The `initialQuery` effect only sends when `messages.length === 0`.
- Once the welcome message exists, `initialQuery` may not fire.
Target difference:
- Clicking workflow cards, agent cards, QVue cards, etc. must reliably start the real backend action.
Required change:
- Track consumed `initialQuery` with a ref instead of `messages.length`.
- Allow initial query to run after welcome message insertion.
- Clear or preserve welcome intentionally, but do not block the backend call.
---
### Gap E — Workflow progress is hardcoded to one job-prep sequence
Current evidence:
- `WorkflowProgress.tsx` has a static six-step `WORKFLOW_STEPS` list.
- Chat infers workflow progress from local step numbers returned by backend chat fallback.
Target difference:
- Progress should come from the active `WorkflowRun`:
- `steps[]`,
- `currentStepId`,
- status,
- agent/module state,
- approval gates,
- artifacts.
Required change:
- Replace static `WORKFLOW_STEPS` with workflow definition/run data.
- Support varied workflows: interview-to-offer, transition, negotiation, promotion, brand engine.
---
### Gap F — API access is inconsistent
Current evidence:
- `/v2/workflows/page.tsx` calls `NEXT_PUBLIC_GROWQR_BACKEND_URL` directly.
- `GrowChat.tsx` sometimes calls backend URL directly and sometimes calls `/api/growqr/...`.
- `/api/growqr/[...path]/route.ts` already exists and handles Clerk auth server-side.
Target difference:
- Browser frontend should prefer `/api/growqr/*` proxy for backend control-plane calls.
- Direct public backend URL should be a fallback only when explicitly needed.
Required change:
- Standardize v2 frontend calls on a small API client:
- `getWorkflowCatalog()`
- `startWorkflow(workflowId, input)`
- `getWorkflowRun(runId)`
- `runWorkflowStep(runId, stepId)`
- `sendChatMessage()`
- Use `/api/growqr/*` by default.
---
### Gap G — Home/navigation is still too dashboard-like for the mockup direction
Current evidence:
- `/v2/page.tsx` has an Apple-like folder idea already, but still mixes fake score widgets, dashboard report cards, long explanatory copy, and many routes.
- `SidebarMinimal.tsx` exposes product sections as a standard SaaS sidebar: Home, Chat, Agents, Workflows, Dashboard, QX Score, Q-Vue.
- The mockup instead frames the product around simple modes and grouped widgets: Home, Workflows, Opportunities, Analytics, Rewards, plus user identity/community modes such as Seeker, Mentor, Events, Community.
Target difference:
- Home should become a visual launchpad with grouped widgets/folders and one primary daily action.
- Navigation should reduce cognitive load. Users should not need to understand every product section before acting.
- The first screen should answer visually: “What should I do today?”, “Which workflow is active?”, “What reward/score changed?”, “Who is helping me?”
Required change:
- Replace dense dashboard sections with widget groups:
- Today / Daily Actions,
- Active Workflows,
- Opportunities / Agents,
- Q Score / Analytics,
- Rewards / Badges.
- Use icon tiles and illustrated cards for catalog entries: Mock Interviews, Mock Tests, Jobs, Courses, Mentorships, Resume, Social Branding, Interview, Role Play, Assessments.
- Keep detailed analytics behind drill-down widgets; do not put dense text/charts on the first view.
- Add micro-interactions only where they clarify state: progress animation, agent typing/working state, reward unlock, workflow step completion.
---
## 3. Big frontend phases
### Phase 1 — Tomorrow sellable-workflow launch UI
Goal: make the frontend safe to sell workflows without fake claims.
Must change:
1. Replace hardcoded workflow cards with backend `GET /workflows` catalog.
2. Replace hardcoded `/workflows/job-application` calls with `/:workflowId` routes once backend exposes them.
3. Make `/v2/workflows` the main launch surface:
- visual mission cards,
- available/active tabs,
- start button,
- active run panel,
- agent squad cards,
- module cards,
- artifact preview tiles,
- Q Score before/after slot.
4. Make `/v2` Home a safe visual launchpad:
- no fake score/report widgets,
- Apple/App-Library-style grouped folders,
- Today action widget,
- Active workflow widget,
- Opportunities/Agents widget,
- Rewards/Badges locked or real.
5. Fix `GrowChat` initialQuery.
6. Remove/deactivate `ChatInterface` local fake responses from launch paths.
7. Hide or lock pages that still show fake metrics: marketplace, qvue, pathways, full dashboard sections.
8. Standardize API calls through `/api/growqr`.
Definition of done:
- A user can select a real workflow from backend catalog.
- Starting the workflow creates a backend run.
- The UI shows real run status/modules/artifacts only.
- If a service is unavailable, the UI shows blocked/unavailable from backend, not fake success.
- No visible fake Q Score, fake experts, fake videos, fake applications, or fake milestones on launch surfaces.
---
### Phase 2 — Gamified low-reading workflow UX
Goal: make the product feel like a playful career mission system for students/freshers/Tier-2/Tier-3 users, using the mockup and iPhone/App Library as interaction references.
Must change:
1. Render backend workflow definitions as visual missions:
- icon/mascot,
- one-line promise,
- estimated time,
- reward/outcome,
- agent squad avatars,
- “Start Mission” CTA.
2. Render workflow runs as maps:
- Start → Diagnose → Build → Practice → Score → Match/Finish.
3. Add Apple-style grouped widgets/folders:
- Workflows,
- Opportunities,
- Pathways/Reports,
- Analytics/Q Score,
- Rewards,
- Social/Productivity.
4. Add artifact cards:
- resume version,
- LinkedIn rewrite,
- interview plan,
- negotiation script,
- promotion evidence packet,
- brand posts.
5. Add score-delta and analytics cards that are visual before textual:
- before/after Q Score ring,
- dimensions improved,
- mini graph/sparkline,
- badges unlocked.
6. Add lightweight mobile-first states:
- one primary CTA,
- short copy,
- visual status,
- low text density,
- voice/text TalkwithME entry point.
7. Add daily personalization feedback:
- like/dislike/filter controls on workflow outputs,
- “show me more like this” chips,
- backend-backed preference state only.
Definition of done:
- Users understand each workflow in under 5 seconds without reading paragraphs.
- Each workflow has visible reward/output cards.
- Home feels like a visual app library/career OS, not a SaaS report dashboard.
- The UX sells outcomes, not internal services.
---
### Phase 3 — Production polish and conversion
Goal: make frontend reliable for paid users and measurable launch.
Must change:
1. Add entitlement states:
- free preview,
- locked premium workflow,
- purchased/active,
- expired/completed.
2. Add durable loading/error states:
- provisioning OpenCode,
- service unavailable,
- waiting for user input,
- approval required,
- retry available.
3. Add run history:
- completed workflows,
- generated artifacts,
- score changes,
- next recommended workflow.
4. Add analytics events:
- catalog viewed,
- workflow clicked,
- workflow started,
- module completed,
- artifact opened,
- payment intent.
Definition of done:
- The frontend is sales-ready, supportable, and measurable without inventing product state.
---
## 4. Frontend agent handoff checklist
Work in this order:
1. Create a frontend API client for `/api/growqr`.
2. Replace workflow discovery with backend catalog.
3. Generalize `/v2/workflows` to multiple workflow IDs.
4. Convert `/v2` Home into a visual launchpad:
- grouped widgets/folders,
- one daily action,
- Active vs Available surfaces,
- no fake metrics.
5. Fix `GrowChat` initial query.
6. Remove `ChatInterface` from launch routes or delete its local response engine.
7. Hide/lock fake-data pages from nav until backend data exists.
8. Convert QX/Dashboard cards to backend-backed empty/real states.
9. Keep copy short and visual-first: icon/illustration + one line + CTA.
Do not work on microservice internals in this frontend pass.

952
growqrApp.md Normal file
View File

@@ -0,0 +1,952 @@
Yeah — this repo is doing something pretty unusual, and honestly pretty smart.
## The shortest possible explanation
This is **not** a normal “frontend ↔ API” app.
Its more like:
- the **UI** is a Next.js app
- the **orchestrator** is a **super-agent router / session broker**
- the **user-service** is the **identity + profile source of truth**
- the domain services are treated like **agents**
- **Redis Streams** is the internal task bus
- **Q-Score** is a cross-cutting scoring engine fed by events extracted from agent outputs
- some flows are **agentized**, some are still **direct REST**, and live audio flows are **direct WebSocket to specialty services**
So the system has **multiple communication lanes**, not one.
---
# 1. The mental model: 4 communication lanes
## Lane A — Direct frontend → service REST
Used for normal CRUD.
Examples:
- frontend → `user-service` for `/users/me`, `/users/ensure`, photo upload, QR
- frontend → `resume-builder` for resumes, versions, export, parse
- frontend → `social-branding` for profiles, analysis history, content generation
- frontend → `interview-service` / `roleplay-service` artifact APIs
This is the boring, standard lane.
---
## Lane B — Frontend → orchestrator WebSocket → domain agents
Used for **page sessions**, **agent actions**, **cross-service flows**, **progressive updates**.
Examples:
- home dashboard
- resume hub/editor actions
- social media page
- job matching
- pathways
- some interview/roleplay setup/feedback flows
This is the **signature architecture** of the app.
---
## Lane C — Domain agent ↔ orchestrator via Redis Streams or A2A HTTP
This is **internal service-to-service orchestration**.
The orchestrator can invoke an agent in two ways:
### Default: Redis Streams
- orchestrator writes task to `tasks:<agent-name>`
- service worker consumes it
- service publishes response messages to `responses:<task_id>`
- orchestrator relays those messages back to frontend
### Fallback: HTTP A2A
- orchestrator POSTs to `/<service>/a2a/tasks`
- service runs the same session logic and returns collected messages
So they built a dual transport layer:
- **event-driven / stream-based**
- with **HTTP fallback**
Thats very distinctive.
---
## Lane D — Direct live media WebSockets
Used for **real-time interview / roleplay audio sessions**.
Examples:
- frontend `useInterviewSession()` connects directly to interview-service
- frontend `useRoleplaySession()` connects directly to roleplay-service
So live voice does **not** go through the orchestrator data path.
Thats another important part of the uniqueness:
**not everything is forced through one gateway.**
---
# 2. UI app: how the frontend is structured
Main app: `frontend/`
Core stack:
- Next.js 16
- React 19
- Clerk auth
- App Router
- Tailwind
- custom hooks for API + agent sessions
---
## 2.1 Frontend has two personalities
The UI is doing **both**:
### A. Standard SaaS frontend
Using API clients like:
- `src/lib/api/users.ts`
- `src/lib/api/resumes.ts`
- `src/lib/api/socialBranding.ts`
These attach Clerk Bearer tokens and call REST endpoints directly.
### B. Agent-driven frontend
Using:
- `src/hooks/useAgentSession.ts`
This hook is the key.
It:
- gets Clerk token
- opens WebSocket to orchestrator:
`ws://.../ws/agent?token=<clerk_jwt>`
- sends:
```json
{ "type": "session_start", "page": "...", "params": {...} }
```
- later sends:
```json
{ "type": "user_action", "action": "...", "params": {...} }
```
And it listens for structured messages like:
- `capabilities_updated`
- `agent_routed`
- `agent_thinking`
- `agent_data`
- `agent_suggestion`
- `agent_activity`
- `agent_error`
- `qscore_loaded`
- `qscore_updated`
- copilot streaming chunks
So the frontend is basically talking to a **message protocol**, not just fetching JSON.
---
## 2.2 Important frontend providers
### `QScoreProvider`
At dashboard layout level:
- `frontend/src/app/(dashboard)/layout.tsx`
This persists Q-Score across dashboard navigation.
### `UserProvider`
In `DashboardLayout.tsx`
This does:
- `usersApi.ensureUser()`
- loads the GrowQR user record
- exposes `user`, `isPro`, `refreshUser`
So Clerk is auth, but **user-service is the app identity profile**.
---
## 2.3 What page loads feel like
When a page uses `useAgentSession(...)`, the frontend is not directly loading page data from the domain service.
Instead:
1. connect to orchestrator
2. orchestrator authenticates
3. orchestrator resolves user context via user-service
4. orchestrator routes page to correct agent
5. agent sends structured messages back
6. UI renders from `latestData[action]`
Example:
- Home page uses:
`useAgentSession(WS_URL, "home")`
- It waits for `dashboard_loaded`
So the page isnt “call GET /dashboard”.
Its more like:
> “Start an agent session for page `home` and stream me the result.”
Thats very different from normal SaaS frontend architecture.
---
## 2.4 Frontend communication split by feature
### Home dashboard
- goes through orchestrator
- page = `"home"`
- routed to `dashboard-service`
### Resume pages
- direct REST for CRUD/export/parse
- orchestrator WS for page session + AI/copilot/page-level orchestration
### Social branding
- direct REST for profiles/analysis/content
- orchestrator WS for page session and agent-like flows
### Settings / profile
- direct REST to `user-service`
- user data also available through orchestrator-resolved context
### Job matching
- orchestrator-driven agent page
### Pathways
- orchestrator-driven agent page
### Interview / roleplay
- setup/feedback pages use orchestrator-style session hooks
- actual live conversation uses **direct WS** to the interview/roleplay service
### Helper chat
Theres also:
- `frontend/src/app/api/chat/route.ts`
That one calls OpenAI directly from Next server route, outside the orchestrator pattern.
So even inside frontend, youve got:
- direct REST
- orchestrated WS
- direct live WS
- direct Next server AI route
---
# 3. Orchestrator: what it really is
Main folder:
- `orchestrator/`
Key file:
- `orchestrator/app/main.py`
- `orchestrator/app/agent/session.py`
## The orchestrator is basically:
### a WebSocket gateway
+ auth layer
+ service discovery layer
+ routing layer
+ context enrichment layer
+ signal extraction layer
+ Q-Score event publisher
+ background workflow coordinator
Thats why it feels unique.
---
## 3.1 What happens when frontend connects
In `orchestrator/app/agent/websocket.py`:
1. WebSocket opens with `?token=<clerk_jwt>`
2. orchestrator verifies Clerk JWT
3. extracts Clerk user id
4. creates `SuperAgentSession`
Then in `SuperAgentSession.run()`:
### Step 1
Send capabilities snapshot
### Step 2
Resolve user identity via `user-service`
### Step 3
Process:
- `session_start`
- `user_action`
- `session_end`
So every agent session begins with:
- who is this user?
- what agents are available?
- whats the current user context?
---
## 3.2 Service discovery is dynamic
Files:
- `orchestrator/app/discovery/registry.py`
- `orchestrator/app/discovery/health.py`
The orchestrator periodically calls:
- `/.well-known/agent-card.json`
- fallback `/.well-known/agent.json`
from each configured agent URL.
It stores:
- agent name
- description
- skills
- health state
So the orchestrator is not hardcoded to just “known APIs”.
It has a **registry of discovered agent capabilities**.
Thats a real agent-style pattern.
---
## 3.3 Routing is page-based and action-based
In `orchestrator/app/agent/session.py`:
### Page routing
`PAGE_TO_AGENT` maps:
- `home` → `dashboard-service`
- `resume-hub` → `resume-builder`
- `social-media` → `social-branding`
- `job-matching` → `matchmaking-service`
- `settings` → `user-service`
- `pathways` → `pathways-service`
- etc.
### Action routing
`ACTION_TO_AGENT` maps actions like:
- `ai_analyze` → `resume-builder`
- `run_analysis` → `social-branding`
- `update_preferences` → `user-service`
- `get_feed` → `matchmaking-service`
- `generate_pathway` → `pathways-service`
So the orchestrator understands:
- “which page belongs to which agent”
- “which user action belongs to which agent”
That makes the frontend simpler: it just emits actions, not service URLs.
---
## 3.4 The orchestrator always resolves user context first
This is one of the most important design choices.
In `_resolve_user_identity()`:
1. call `user-service` action `view_profile`
2. get the real user profile
3. extract the app UUID
4. enrich with skills from:
- `resume-builder /api/state/{clerk_id}`
- `social-branding /api/state/{clerk_id}`
So the orchestrator creates a **portable user context** that can be sent to any domain agent.
That means agents dont each need to re-fetch identity basics every time.
This is a huge reason the architecture feels “agentic” instead of “API-ish”.
---
## 3.5 Dual transport: Redis first, HTTP fallback
Files:
- `orchestrator/app/a2a/redis_transport.py`
- `orchestrator/app/a2a/client.py`
### Redis mode
- publish task to `tasks:<agent>`
- subscribe to `responses:<task_id>`
- stream messages to frontend in real time
### HTTP mode
- POST to `/<agent>/a2a/tasks`
- get collected messages back
So the orchestrator can treat agents as:
- synchronous HTTP responders
- or event-driven streaming workers
Thats sophisticated.
---
## 3.6 Q-Score is deeply embedded into orchestration
This is another unique thing.
The orchestrator doesnt just route actions.
It also watches agent outputs and turns them into **scoring signals**.
Files:
- `orchestrator/app/qscore/signal_mapper.py`
- `publisher.py`
- `subscriber.py`
- `client.py`
### On session init
It:
- fetches latest Q-Score over HTTP from qscore-service
- registers callback for live score updates via Redis stream
- publishes engagement + onboarding signals
### After domain-agent responses
It scans returned messages:
- resume analysis
- LinkedIn analysis
- job matching actions
- interview review
- roleplay review
- pathway progress
Then extracts signals like:
- `resume.ats_compatibility`
- `linkedin.headline_quality`
- `matching.feed_active`
- `interview.overall_score`
- `pathway.completion_pct`
Then publishes them to:
- `qscore.signal_events`
So the orchestrator is not just a router.
It is also a **semantic event interpreter**.
Thats rare.
---
## 3.7 Background workflows are coordinated here
Endpoint:
- `POST /api/v1/background-task`
Used by:
- `resume-builder` after resume upload
- `social-branding` after LinkedIn fetch/connect
Flow:
1. service notifies orchestrator
2. orchestrator resolves user context
3. dispatches background task to agent
4. collects messages
5. extracts Q-Score signals
6. extracts auto-populate info
7. PATCHes `user-service /users/auto-populate`
So the orchestrator also acts like a **workflow engine**.
---
# 4. User-service: why its more important than it first looks
Main folder:
- `user-service/`
Key files:
- `app/main.py`
- `app/api/v1/users.py`
- `app/api/v1/webhooks.py`
- `app/agent/session.py`
This service is not just “users table CRUD”.
It is the **identity gateway** of the whole platform.
---
## 4.1 It is the source of truth for app-level user state
It owns:
- GrowQR user record
- Clerk id mapping
- email / first_name / last_name
- avatar_url
- plan
- preferences
- metadata
- QR code data
- profile photo
- onboarding state (stored in preferences)
This is the canonical application profile.
---
## 4.2 It bridges Clerk identity to internal GrowQR identity
Frontend auth is Clerk.
But Q-Score and some internal flows need a stable internal user UUID.
That comes from `user-service`.
So the mapping is basically:
- Clerk user id → auth identity
- GrowQR user UUID → internal cross-service identity
Thats why orchestrator hits user-service first.
---
## 4.3 It supports three access styles
### 1. Direct REST from frontend
Examples:
- `/api/v1/users/me`
- `/api/v1/users/ensure`
- `/api/v1/users/me/photo`
- `/api/v1/users/me/qr-code`
### 2. Agent-style access
Via:
- `/ws/agent`
- `/a2a/tasks`
So user-service itself behaves like an agent.
### 3. Internal state endpoint
- `/api/state/{clerk_id}`
Used by dashboard-service and orchestrator.
So user-service exposes both:
- user-facing API
- internal aggregation API
- agent protocol surface
---
## 4.4 It auto-creates users on first sign-in
In `UserProvider`, frontend calls:
- `ensureUser()`
Server side `/users/ensure`:
- if user exists → return it
- if not → fetch from Clerk API if possible
- create GrowQR user row
- generate QR code
So app account creation is **lazy and synchronized** off Clerk login.
---
## 4.5 It stores onboarding state
The frontend hook:
- `useOnboarding()`
writes onboarding into:
- `user.preferences.onboarding`
This is clever because onboarding becomes part of the shared user context, not some isolated frontend state.
That means orchestrator and Q-Score can use it.
---
## 4.6 It handles Clerk webhooks
In `app/api/v1/webhooks.py`:
Supported:
- `user.created`
- `user.updated`
- `user.deleted`
- `session.created`
Effects:
- create/update/soft-delete user
- update last sign-in
- trigger downstream cleanup on delete
So user-service is the **sync point between external auth identity and internal domain data**.
---
## 4.7 It also owns QR/public identity features
It handles:
- uploaded profile photo
- branded QR generation
- public profile endpoint
- QR regeneration
Thats not just admin/user metadata. It also powers the outward-facing GrowQR identity layer.
---
## 4.8 Auto-populate is a hidden important feature
Orchestrator can call:
- `PATCH /api/v1/users/auto-populate`
It fills empty user/profile/settings fields based on:
- parsed resume data
- LinkedIn profile data
But only if those fields are empty.
That creates a very smooth onboarding loop:
- upload resume / connect LinkedIn
- AI/background processing runs
- settings fill themselves
This is one of the better-designed pieces.
---
# 5. Why this architecture feels unique
Because the services arent just APIs.
They are treated like **page/domain agents** with a common invocation model.
## The pattern is:
Each service has a central session object, like:
- `UserAgentSession`
- `DashboardAgentSession`
- similar in resume/social/etc.
That same session logic can be invoked through:
### A. native WebSocket
actual user-agent page session
### B. HTTP A2A
via `/a2a/tasks`
### C. Redis Stream worker
consumes `tasks:<agent>` and publishes responses
That means **one domain behavior implementation** is reused across multiple transports.
Thats actually a strong architectural idea.
---
# 6. How each service communicates with others
Heres the clean map.
## 6.1 Frontend
Talks to:
- `user-service` via REST
- `resume-builder` via REST
- `social-branding` via REST
- `orchestrator` via WS
- `interview-service` via direct WS + REST
- `roleplay-service` via direct WS + REST
- internal Next `/api/chat` route for helper chat
---
## 6.2 Orchestrator
Talks to:
- `user-service` for identity resolution + metadata persistence + auto-populate target
- `resume-builder` for page/actions + skill enrichment + background parse/analyze
- `social-branding` for page/actions + skill enrichment + background analysis
- `dashboard-service` for home page payload
- `matchmaking-service` for job matching actions
- `pathways-service` for pathway actions
- `qscore-service` for initial read + signal publication + update subscription
Transport used:
- Redis Streams preferred
- HTTP A2A fallback
- HTTP internal state calls for enrichment
---
## 6.3 Dashboard-service
Talks to:
- `user-service /api/state/{clerk_id}`
- `resume-builder /api/state/{clerk_id}`
- `social-branding /api/state/{clerk_id}`
- `qscore-service /v1/qscore/{uuid}`
It acts like an **aggregator service**:
- collect distributed state
- merge
- evaluate card rules
- compute lifecycle
- return `dashboard_loaded`
So dashboard-service is basically a **read model / composition engine**.
---
## 6.4 Resume-builder
Talks to:
- orchestrator for background-task kickoff after upload
- likely user auth verification through Clerk token on direct REST
- exposes state to orchestrator/dashboard
- emits analysis data consumed by orchestrator → qscore
It is both:
- CRUD/document service
- AI analysis agent
---
## 6.5 Social-branding
Talks to:
- orchestrator for background-task kickoff after LinkedIn profile connect/fetch
- exposes state to orchestrator/dashboard
- emits analysis data that becomes qscore signals
It is both:
- profile ingestion service
- AI profile-analysis agent
---
## 6.6 User-service
Talks to:
- Clerk webhooks
- resume/social cleanup endpoints on delete
- orchestrator
- dashboard-service
- frontend
It is the central identity/state hub.
---
## 6.7 Qscore-service
Talks to:
- orchestrator via HTTP read + Redis streams
- receives signals on `qscore.signal_events`
- computes score
- publishes updates on `qscore.score_updates`
So Qscore is event-fed, not directly computed inline on every user request.
Thats a strong decoupling.
---
## 6.8 Matchmaking-service
Observed pattern:
- external sibling service
- has Redis stream worker + A2A endpoints
- orchestrator routes job-matching actions to it
- likely handles scraping, ranking, worker queues
So it fits the **agentized service** model.
---
## 6.9 Pathways-service
Observed pattern:
- external sibling service
- Redis worker + A2A endpoints
- has `/api/state/{clerk_id}`
- orchestrator routes pathway actions to it
Also fits the agentized pattern.
---
## 6.10 Interview-service / Roleplay-service
These are more hybrid.
### Definitely observed:
- direct REST configure/review endpoints
- direct live WebSocket session endpoints
- frontend hooks connect directly for live audio
### Architectural meaning:
These are **specialized real-time media services**.
They dont cleanly fit the normal agent/session transport path the way user/resume/social/dashboard/pathways/matchmaking do.
So the system is not “pure agent architecture”.
It is **agent architecture + specialized realtime sidecars**.
That hybrid is part of what makes it interesting.
---
# 7. End-to-end flows
## Flow A — User opens Home
1. frontend connects to orchestrator WS
2. orchestrator verifies Clerk JWT
3. orchestrator asks user-service for profile
4. orchestrator enriches user context from resume/social state
5. orchestrator fetches initial Q-Score
6. frontend sends `session_start(page="home")`
7. orchestrator routes to dashboard-service
8. dashboard-service fetches state from user/resume/social/qscore
9. dashboard-service builds `dashboard_loaded`
10. orchestrator relays it to frontend
11. later Q-Score updates can stream in live
Thats a very nontraditional home-page load.
---
## Flow B — User changes settings
1. frontend calls `user-service /users/me` directly
2. user-service updates preferences
3. those preferences become part of future orchestrator-resolved context
4. Q-Score / pathways / matching can later use them
So settings are not isolated—they feed the broader system.
---
## Flow C — User uploads resume during onboarding
1. frontend uploads PDF directly to `resume-builder`
2. resume-builder stores PDF + thumbnail
3. resume-builder triggers orchestrator `/api/v1/background-task`
4. orchestrator resolves user context
5. orchestrator dispatches `bg_parse_analyze`
6. resume-builder parses PDF, builds structured content, runs AI analysis
7. orchestrator extracts:
- auto-populate fields
- qscore signals
8. orchestrator PATCHes `user-service /users/auto-populate`
9. user settings/profile become prefilled
Thats a really elegant async flow.
---
## Flow D — User connects LinkedIn
1. frontend hits social-branding
2. social-branding stores/fetches profile
3. social-branding triggers orchestrator background task
4. orchestrator dispatches `bg_analyze`
5. social-branding emits `profile_loaded`, `profile_scored`, `analysis_complete`
6. orchestrator:
- extracts auto-populate fields
- publishes qscore signals
- updates user-service
Again: domain output becomes shared platform intelligence.
---
## Flow E — User starts interview live session
1. frontend likely uses orchestrator/setup flow to configure session metadata
2. interview-service returns `session_id`
3. frontend opens direct WS to interview-service
4. audio packets stream directly
5. review/artifacts are later fetched from interview-service
6. orchestrator may later use review/history outputs for Q-Score
So live media bypasses the general agent path for latency reasons.
---
# 8. What makes this architecture strong
## Strengths
### 1. Clear separation of concerns
- UI
- identity
- orchestration
- domain intelligence
- scoring
- realtime media
### 2. Reusable agent/session abstraction
Same business session logic can work over:
- frontend WS
- HTTP A2A
- Redis worker
### 3. Great for incremental AI adoption
AI doesnt have to be one giant “assistant”.
Each domain agent is specialized.
### 4. Cross-service intelligence
Resume + social + onboarding + engagement all feed Q-Score.
### 5. Good async workflow design
Background tasks avoid blocking user flows.
### 6. Nice read-model approach on dashboard
Dashboard-service composes distributed state into one home payload.
---
# 9. Tradeoffs / complexity
## This architecture is powerful, but expensive mentally.
### 1. Multiple protocols
You have:
- REST
- orchestrator WS
- Redis streams
- A2A HTTP
- direct media WS
Thats a lot to hold in your head.
### 2. Mixed patterns
Some services are fully agentized.
Some are direct APIs.
Some are hybrid realtime.
### 3. Debugging is multi-hop
A page issue might involve:
- Clerk token
- orchestrator auth
- user-service resolution
- agent routing
- Redis stream worker
- qscore side effects
### 4. Service discovery + routing adds indirection
Great power, but more moving parts.
### 5. Some services live outside repo root
Operationally a bit awkward.
---
# 10. The cleanest way to describe this app
If I had to describe GrowQR to an engineer in one paragraph:
> GrowQR is a hybrid microservice platform where the frontend uses both direct REST and a central orchestrator WebSocket. The orchestrator authenticates users once, resolves a shared user context through user-service, dynamically discovers domain agents, routes page sessions and actions to those agents over Redis Streams or HTTP A2A, extracts semantic signals from their outputs, and feeds those signals into a separate Q-Score engine. Meanwhile, traditional CRUD and low-latency media workflows still use direct service APIs and direct WebSockets. So the system combines SaaS API architecture, agent orchestration, event-driven messaging, and realtime media pipelines in one platform.
Thats why it feels unique.
---
# 11. The single most important insight
The **user-service + orchestrator combo** is the heart.
- **user-service** = “who is this user in GrowQR?”
- **orchestrator** = “given this user and this page/action, which domain intelligence should run now?”
Everything else plugs into that.
---
If you want, next I can do one of these:
1. **draw you a plain-English sequence diagram** for the whole app
2. **map every page in frontend to its backend path/service**
3. **explain only the orchestrator internals deeply**
4. **make you an architecture doc you can share with your team**

View File

@@ -0,0 +1,403 @@
# GrowQR Integration Problem Analysis
## Current Pain Points
### 1. Hardcoded Routing Maps
The orchestrator has hardcoded `PAGE_TO_AGENT` and `ACTION_TO_AGENT` dictionaries in `session.py`. When new services are added or actions renamed, these maps must be updated, requiring:
- Code changes to orchestrator
- Redeployment of orchestrator
- Coordination between your team (service changes) and original team (orchestrator updates)
### 2. Redis Streams Complexity
Current event-driven architecture uses Redis Streams with specific naming conventions:
- Stream naming: `tasks:{agent_name}`
- Response channels: `responses:{task_id}`
- Message format with specific JSON schema
- Pub/sub completion sentinels (`__task_complete__`)
Contributors must understand this protocol, implement consumers, handle backpressure, etc.
### 3. Dual Transport Maintenance
Services must implement both:
- Redis Stream worker (for streaming/async)
- HTTP A2A endpoints (for synchronous fallback)
This doubles the integration surface area.
### 4. Contract Breaking on Changes
When you modify microservices:
- Action names change
- Message formats evolve
- New parameters added
- Response structures modified
The original team must update all consumers (orchestrator, other services) to match.
### 5. No Runtime Tool Registration
Agent cards (`/.well-known/agent-card.json`) are static JSON files. To add/modify skills:
- Change JSON
- Redeploy service
- Orchestrator must rediscover
There's no dynamic "tool marketplace" where contributors can register capabilities at runtime.
## Goals for Improvement
1. **Minimize breaking changes** - Changes to services shouldn't require orchestrator updates
2. **Simplify contributor integration** - New developers should add tools without deep Redis/protocol knowledge
3. **Dynamic tool management** - Frontend-visible tools should be registrable at runtime
4. **Pluggable interface** - SDK-like experience without building a full SDK
5. **Preserve architecture** - Keep the 4-lane model, orchestrator pattern, Q-Score signals
## Potential Solution Paths
### Path A: Dynamic Tool Registry (Database-Driven)
Replace hardcoded maps with a database table that stores:
- Tool ID, name, description
- Target agent/service URL
- Input schema (JSON Schema)
- Output schema (JSON Schema)
- Routing rules (page patterns, action patterns)
- Version info
**Pros:**
- Runtime tool registration
- Versioning support
- Frontend can show available tools dynamically
- No orchestrator redeploy for new tools
**Cons:**
- Still need to define schemas
- Database migration required
- Some complexity in registry UI/management
### Path B: HTTP-Only Standardization (Simplify Transport)
Standardize on HTTP A2A for ALL service communication. Remove Redis Streams complexity.
**Changes:**
- All services implement `/a2a/tasks` endpoint
- Standardized request/response format
- Streaming via SSE (Server-Sent Events) instead of Redis pub/sub
- Orchestrator routes all traffic via HTTP
**Pros:**
- Single transport to understand
- HTTP is familiar to all developers
- Easy to test/debug with curl/Postman
- Load balancing built-in
- No Redis consumer complexity
**Cons:**
- Loses Redis persistence/replay capability
- Slightly higher latency (acceptable?)
- WebSocket to HTTP bridging needed
### Path C: Schema Registry + Code Generation
Maintain a central schema registry (like Confluent Schema Registry or simple JSON Schema store):
- Services register their message schemas
- Orchestrator validates messages against schemas
- Code generation for type-safe clients
- Schema evolution rules (backward/forward compatibility)
**Pros:**
- Strong typing
- Schema evolution managed
- Clear contracts
**Cons:**
- Complex to implement
- Still requires coordination
- Overhead for simple services
### Path D: GraphQL Federation
Replace REST/A2A with GraphQL:
- Single GraphQL gateway (orchestrator becomes gateway)
- Services expose GraphQL schemas
- Frontend queries exactly what it needs
- Natural stitching of services
**Pros:**
- Single query for multi-service data
- Strong typing
- Introspection = automatic discovery
- Frontend-driven queries
**Cons:**
- Major architectural shift
- Learning curve for team
- Q-Score signals need separate path
- Breaking change to entire system
### Path E: Plugin Architecture with Self-Registration
Services self-register at startup via a "Plugin Registry" API:
```python
# In service startup
await plugin_registry.register({
"service_name": "interview-service",
"version": "2.0.0",
"tools": [
{
"tool_id": "configure_interview",
"name": "Configure Interview",
"endpoint": "/a2a/tasks",
"input_schema": {...},
"triggers": ["page:interview", "action:configure_interview"],
"outputs": ["interview_configured", "qscore_signals"]
}
]
})
```
**Pros:**
- Services describe themselves
- No hardcoded maps
- Runtime discovery
- Can include health checks
**Cons:**
- Services must implement registration logic
- Registration order matters
- Need deregistration/cleanup
### Path F: OpenAPI-Based Dynamic Client Generation
Services expose OpenAPI specs at `/.well-known/openapi.json`:
- Orchestrator fetches specs
- Generates client code dynamically (or uses generic client)
- Routes based on operationIds
- Validates requests/responses
**Pros:**
- Industry standard
- Auto-generated docs
- Code generation tools exist
- Language agnostic
**Cons:**
- Still need routing logic
- OpenAPI can be verbose
- Doesn't solve the action/page routing problem
### Path G: gRPC with Reflection
Replace HTTP A2A with gRPC:
- Services define .proto files
- gRPC reflection for discovery
- Strongly typed, efficient
- Streaming support built-in
**Pros:**
- Type safety
- Performance
- Streaming
- Reflection = discovery
**Cons:**
- Major architectural change
- Frontend needs gRPC-web or gateway
- Learning curve
- Overkill for simple CRUD
## Recommended Hybrid Approach
Based on the constraints (minimal breaking changes, contributor-friendly, pluggable), I recommend a **hybrid approach combining Path A + Path B + Path E**:
### Phase 1: Dynamic Tool Registry (Immediate Win)
**Create a Tool Registry Service (or add to orchestrator):**
```python
# Tool Registry Schema
tool_registry = {
"tool_id": "resume_analyze",
"name": "AI Resume Analysis",
"description": "Analyzes resume for ATS compatibility",
"service_name": "resume-builder", # Maps to agent name
"service_url": "http://resume-builder:8000",
"triggers": {
"pages": ["resume-hub", "resume-editor"],
"actions": ["ai_analyze", "analyze_resume"],
"skills": ["resume.analysis"]
},
"input_schema": {
"type": "object",
"properties": {
"resume_id": {"type": "string"},
"deep_analysis": {"type": "boolean"}
},
"required": ["resume_id"]
},
"output_schema": {
"type": "object",
"properties": {
"score": {"type": "number"},
"suggestions": {"type": "array"}
}
},
"qscore_signals": ["resume.ats_score", "resume.completeness"],
"version": "2.1.0",
"enabled": True,
"created_by": "contributor-xyz",
"created_at": "2024-01-15"
}
```
**Changes to Orchestrator:**
1. Replace hardcoded `PAGE_TO_AGENT` and `ACTION_TO_AGENT` with registry lookups
2. Cache registry in memory with periodic refresh
3. New admin endpoints for tool CRUD
4. Frontend can query available tools for a page
### Phase 2: HTTP-First with Optional Redis (Simplify Transport)
**Standardize on HTTP A2A as primary transport:**
1. Make HTTP A2A the default (already implemented)
2. Deprecate Redis Streams for new services (keep for existing)
3. Add SSE streaming support for real-time updates
4. Contributors only need to implement: `POST /a2a/tasks`
**Service Template for Contributors:**
```python
# Minimal service template
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class TaskRequest(BaseModel):
task_id: str
action: str
params: dict
user_id: str
user_context: dict | None = None
@app.post("/a2a/tasks")
async def handle_task(request: TaskRequest):
# Route to appropriate handler
if request.action == "my_tool_action":
result = await my_tool.execute(request.params, request.user_context)
return {
"task_id": request.task_id,
"status": "completed",
"messages": [{
"type": "agent_data",
"action": "my_tool_complete",
"data": result
}]
}
```
### Phase 3: Self-Registration with Health Checks (Plugin Architecture)
**Services self-register on startup:**
```python
# Service startup
async def register_tools():
async with httpx.AsyncClient() as client:
await client.post(
"http://orchestrator:8000/api/v1/tools/register",
json={
"service_name": "my-new-service",
"tools": [
{
"tool_id": "my_tool",
"triggers": {
"pages": ["my-page"],
"actions": ["my_action"]
},
"endpoint": "/a2a/tasks",
"health_check": "/health"
}
]
},
headers={"Authorization": f"Bearer {REGISTRATION_TOKEN}"}
)
```
**Orchestrator enhancements:**
- Accept dynamic registrations
- Health check polling
- Automatic deregistration on unhealthy services
- Tool versioning (multiple versions of same tool)
### Phase 4: Frontend Tool Marketplace
**Allow dynamic tool enabling from frontend:**
```typescript
// Admin interface
interface ToolConfig {
toolId: string;
enabled: boolean;
visibleToUsers: boolean;
requirePlan: 'free' | 'pro' | 'enterprise';
customParams: Record<string, any>;
}
// Users see tools based on registry + their plan
const availableTools = await fetch('/api/v1/tools/available?page=resume-hub');
```
## Implementation Roadmap (Minimal Breaking Changes)
### Week 1-2: Registry Foundation
1. Create `ToolRegistry` class in orchestrator (in-memory first)
2. Add `/api/v1/tools` CRUD endpoints
3. Load hardcoded maps into registry at startup
4. Switch routing to use registry lookups
**Breaking change:** None - just refactoring
### Week 3-4: Service Self-Registration
1. Add registration endpoint to orchestrator
2. Create simple registration helper library
3. Update one service (e.g., interview-service) to self-register
4. Test end-to-end
**Breaking change:** None for existing services
### Week 5-6: Frontend Integration
1. Add tool discovery API: `/api/v1/tools?page={page}`
2. Frontend fetches available tools per page
3. Dynamic UI rendering based on tool registry
4. Admin interface for tool management
**Breaking change:** None - additive feature
### Week 7-8: HTTP-First Migration
1. Ensure all services have HTTP A2A endpoints
2. Switch orchestrator default to HTTP
3. Add SSE streaming for real-time updates
4. Document contributor template
**Breaking change:** Redis becomes optional (not default)
### Week 9-10: Contributor SDK (Lightweight)
1. Python decorator library:
```python
from growqr_sdk import tool, register_service
@tool(
tool_id="analyze_resume",
triggers=["page:resume-hub", "action:analyze"]
)
async def analyze_resume(params, user_context):
# Implementation
return {"score": 85}
register_service(
name="my-service",
orchestrator_url="http://orchestrator:8000",
tools=[analyze_resume]
)
```
2. JavaScript/TypeScript equivalent for Node services
## Summary: Why This Works
1. **Minimal breaking changes**: Existing services keep working, Redis optional
2. **Contributor-friendly**: Single HTTP endpoint to implement, decorator SDK optional
3. **Pluggable**: Runtime registration, dynamic UI, no orchestrator redeploy
4 **Preserves architecture**: Still 4-lane, still orchestrated, still Q-Score signals
5 **Your team benefits**: You change services independently, original team gets stability
6 **Original team benefits**: Less integration code, dynamic capabilities, easier debugging
The key insight: **The orchestrator should ask "what tools are available?" not "is this action in my hardcoded map?"**

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,818 @@
# GrowQR Q-Score Microservice Implementation Plan
Status: Draft for team confirmation in review meeting
Owner: Rahul (Engineering)
Prepared on: 2026-02-11
Related docs: `growqr/Q-Score_Service.md`
---
## 1) Executive Summary
We are building a Python FastAPI + Postgres microservice that is the core Q-Score engine.
MVP behavior:
- Accept processed/scored signals (per-rule/per-input) from other services via a pub/sub stream.
- Compute Q-Score from those stored signals using the internal formula (CI/SV, pillar weights, pillar CI, contributions).
- Return and store a full explainable breakdown (rule-level + pillar-level + CI/SV math).
- Expose a small surface area to read signals and read the latest computed Q-Score.
- Publish live Q-Score updates so the orchestrator agent receives changes instantly.
Additional requirements (post-meeting):
- Multi-tenant from day 1: every signal and score is keyed by `org_id`.
- Formula can vary by profession/profile type (e.g., student vs professor) within an org.
- Team members must be able to update formulas via API (in addition to JSON-on-disk).
Explicitly out of scope for this delivery:
- Tier assignment (removed for now).
- Any upstream processing or enrichment (LinkedIn scraping, resume parsing/ATS, education validation, etc.).
- Complex multi-broker support (we start with one broker; can swap later).
Target: delivery ASAP; pub/sub may extend delivery by 1-2 days beyond Saturday if needed.
---
## 2) Confirmed Product/Engineering Decisions
These are locked based on latest discussion:
1. This service is the Q-Score calculation engine only.
2. All rule processing happens outside this service. This service only accepts processed/scored signals.
3. GET/read endpoint must return full scoring transparency:
- each rule score
- each pillar score and contribution
- CI/SV values and final math
4. Engagement signals exist but are not required for initial (day-1) score computations.
5. Auth is deferred; keep middleware hook to add later without endpoint logic rewrite.
6. Pillar 11 (Recognition & Rewards) uses 3 onboarding achievements; points mapping is pending confirmation.
7. Goals signals can be ingested and stored now; they do not impact score in current MVP.
8. Pillar CI formula clarification:
```
Pillar_CI = weighted average of input CIs contributing to that pillar
weight_i = proportion of pillar data points from input_i
```
Where "data points" for v1 = number of rules from that input used in that pillar.
9. For Saturday, keep orchestration simple:
- no separate job queue system (e.g., RQ)
- use a Redis Stream consumer worker + a small scheduler/micro-batcher for near-real-time updates
10. Signal storage must be versioned per user:
- we keep an append-only ledger of every ingested signal update (`signal_ledger`)
- we keep a per-user latest materialized view/table for fast compute (`user_signal_latest`)
- we store every computed Q-Score run (`qscore_runs`) to track how outputs evolve over time
11. Provide a validation endpoint for producers (fire-and-forget): upstream services can call a check endpoint with `user_id`, `signal_id`, and `score` to validate that the signal is acceptable for the current formula registry.
12. Pub/sub is required:
- orchestrator agent publishes a live stream of signals for each user
- Q-Score engine consumes signals and publishes a live stream of Q-Score updates
- agent subscribes to Q-Score updates (bi-directional communication via streams)
13. Freshness target: score update latency should be < 10 seconds.
- intermediate updates are acceptable
- compute/publish is paced (micro-batched) to handle continuous signal dumps
---
## 3) Scope
### MVP Scope (this sprint)
- Signal ingest (stream-based; plus HTTP fallback endpoint)
- Compute Q-Score endpoint (writes a qscore run)
- Read endpoints for signals and latest Q-Score run
- Scoring engine (signals -> rules -> inputs -> pillars -> final Q)
- Postgres persistence (signals + qscore history)
- Pub/sub broker (Redis Streams) + consumer/producer worker
- Docker Compose local stack (API + Postgres + Redis + worker)
### Future Scope (not blocking MVP)
- Full auth middleware implementation
- Additional signals / pillars / formula versions (Excel-driven expansion)
- Batch recompute tuning (dynamic micro-batching, backpressure, autoscaling)
- Broker swap (Kafka/NATS/etc.) behind a small adapter layer if needed
---
## 4) System Architecture
## Components
1. **FastAPI API service**
- request validation
- orchestration
- scoring invocation
- DB writes/reads
2. **Scoring engine module (pure Python)**
- deterministic aggregation and formula application
- CI/SV calculations
- pillar aggregation and contributions
- final score output
3. **Postgres**
- stored signals (latest)
- optional signal event log (append-only)
- qscore history
4. **Redis (Streams)**
- input signal stream (agent -> qscore)
- output score update stream (qscore -> agent)
5. **Worker process**
- consumes input signal stream
- writes ledger + latest state
- recomputes Q-Score (micro-batch)
- publishes score update events
Notes:
- This service does not fetch/enrich any upstream data. Upstream services are responsible for producing scored signals.
---
## 5) High-Level Flows
### Flow A: Live Signal Publish (agent -> qscore)
1. Orchestrator agent publishes signal events to the input stream.
2. Worker consumes signal events.
3. Worker appends each signal update into `signal_ledger` (append-only history).
4. Worker upserts latest signal values into `user_signal_latest`.
5. Worker marks the user as dirty for compute (e.g., updates `user_dirty.last_signal_at`).
Pacing behavior (continuous stream):
- Worker schedules computes per user using a pacer (debounce + max staleness).
- Recency-first priority for user updates; periodic sweep ensures no long-running backlog.
### Flow B: Q-Score Compute
Two triggers are supported:
1) Manual compute-now:
1. Client/producer calls `POST /v1/qscore/compute` with `user_id`.
2. API reads latest signals for user from `user_signal_latest`.
3. Engine computes input CI/SV, pillar scores, pillar CI, contributions, and final Q.
4. API writes a new row in `qscore_runs` with full breakdown.
5. API returns score + breakdown.
2) Scheduled batch compute:
1. Scheduler runs every `BATCH_INTERVAL_SECONDS` (default: 300) and checks if there are dirty users.
2. For each dirty user, compute Q-Score from `user_signal_latest`.
3. Write `qscore_runs` and mark user clean.
Additionally (live updates):
- Worker performs micro-batched computes when new signal events arrive (debounced per user).
- When a user's Q-Score changes, worker publishes an update event to the output stream.
Freshness guarantee (configurable):
- even under continuous events, each dirty user should get recomputed at least once per `MAX_STALENESS_MS` (default: 10000)
### Flow C: Read
1. Client calls `GET /v1/signals/{user_id}` to read latest signals.
2. Client calls `GET /v1/qscore/{user_id}` to read latest Q-Score + breakdown.
---
## 6) API Endpoints
## 6.1 Signal Ingest
`POST /v1/signals/ingest`
Purpose:
- HTTP fallback for producers that cannot publish directly to the broker.
- Server validates and then publishes into the input stream.
Profession handling:
- If `profession` is provided, the service upserts it into `user_profile`.
- If `profession` is omitted, the service uses the existing `user_profile.profession`.
- If neither exists, the service uses a default profession (configurable) and records it.
Request (example):
```json
{
"org_id": "growqr",
"user_id": "b5f9e91f-6a95-4f2f-9f11-4f8f7f5f4c77",
"profession": "student",
"source": "social_branding_service",
"signals": [
{
"signal_id": "linkedin.account_connected",
"present": true,
"score": 100,
"raw": "CONNECTED"
},
{
"signal_id": "resume.ats_compatibility",
"present": true,
"score": 72,
"raw": {"ats_score": 72}
}
],
"occurred_at": "2026-02-11T12:00:00Z"
}
```
Response (example):
```json
{
"org_id": "growqr",
"user_id": "b5f9e91f-6a95-4f2f-9f11-4f8f7f5f4c77",
"formula_version": "v1",
"upserted": 2
}
```
## 6.2 Compute Q-Score
`POST /v1/qscore/compute`
Request (example):
```json
{
"org_id": "growqr",
"user_id": "b5f9e91f-6a95-4f2f-9f11-4f8f7f5f4c77"
}
```
Response (example):
```json
{
"org_id": "growqr",
"user_id": "b5f9e91f-6a95-4f2f-9f11-4f8f7f5f4c77",
"q_score": 67.42,
"profession": "student",
"calculated_at": "2026-02-11T12:01:10Z",
"breakdown": {
"inputs": {},
"rules": {},
"pillars": {},
"math": {}
}
}
```
## 6.3 Read Latest Score (full explainability)
`GET /v1/qscore/{user_id}`
Query params:
- `org_id`
Returns latest `qscore_runs.breakdown` in full detail.
## 6.4 Read Latest Signals
`GET /v1/signals/{user_id}`
Query params:
- `org_id`
Returns latest stored signals for the user (including `present`, `score`, and `raw`).
## 6.5 Signal Check (producer validation)
`POST /v1/signals/check`
Purpose:
- Producer-side validation so upstream can verify a signal is acceptable for the current registry before ingesting.
Request (example):
```json
{
"org_id": "growqr",
"user_id": "b5f9e91f-6a95-4f2f-9f11-4f8f7f5f4c77",
"profession": "student",
"signal_id": "resume.ats_compatibility",
"score": 72,
"raw": {"ats_score": 72}
}
```
Response (example):
```json
{
"valid": true,
"errors": [],
"warnings": []
}
```
Validation rules (v1):
- `signal_id` exists in current formula registry OR is in an allowed "unknown" namespace list (configurable)
- `score` is numeric and within `0..100`
- optional metadata size limits (to protect DB)
## 6.6 Registry Endpoints (sanitized)
`GET /v1/registry/signals`
Returns the list of accepted `signal_id`s and minimal metadata needed by producers (no secret sauce formula details).
Query params (recommended):
- `org_id`
- `profession`
`POST /v1/formula/reload`
Reload formula JSON from disk and swap in-memory formula if validation passes (auth to be added later).
## 6.7 Formula Management (team updates)
We support both:
- JSON-on-disk for version control
- DB-backed formula definitions for API updates
Formula resolution (which formula is used for a user):
1) Read `user_profile.profession` (set via ingest).
2) Resolve active formula version for `(org_id, profession)`.
3) Allow per-user override via `user_profile.formula_version_override` (future).
4) Effective formula key: `{org_id}:{profession}:{version}`.
Filesystem layout (when `FORMULA_STORE=filesystem`):
- `FORMULA_DIR/{version}/{profession}/formula.json`
DB layout (when `FORMULA_STORE=db`):
- `formula_definitions` rows keyed by `(org_id, profession, version)`.
Endpoints:
`GET /v1/formulas`
- lists available formulas (org_id + profession + version + active)
`PUT /v1/formulas/{org_id}/{profession}/{version}`
- upserts a formula JSON blob into Postgres
`POST /v1/formulas/{org_id}/{profession}/activate`
- sets the active formula version for a profession within an org
`GET /v1/users/{org_id}/{user_id}/profile`
- returns the stored profession + active formula resolution (debugging)
## 6.8 Stream Contracts (pub/sub)
Input stream (signals):
- stream name (default): `qscore.signal_events`
- event shape matches `POST /v1/signals/ingest` payload
Output stream (qscore updates):
- stream name (default): `qscore.score_updates`
- event shape (example):
```json
{
"org_id": "growqr",
"user_id": "b5f9e91f-6a95-4f2f-9f11-4f8f7f5f4c77",
"profession": "student",
"q_score": 67.42,
"formula_version": "v1",
"formula_id": "growqr:student:v1",
"qscore_run_id": "...",
"events_considered": {
"ledger_seq_from": 1201,
"ledger_seq_to": 1215,
"count": 15,
"sample_ledger_seqs": [1201, 1202, 1203]
},
"changed": true,
"created_at": "2026-02-11T12:01:10Z",
"breakdown": {"inputs": {}, "rules": {}, "pillars": {}, "math": {}}
}
```
Note:
- agent subscribes to the output stream to receive score updates instantly.
- agent can also read the latest computed value from Redis key `qscore:latest:{org_id}:{user_id}` (updated on every publish).
- `ledger_seq_from` is typically `user_dirty.last_computed_seq + 1` and `ledger_seq_to` is `user_dirty.last_signal_seq` at compute time.
---
## 7) Scoring Model Design
## 7.1 Input CI
For each input `i`:
```
SV_i = present_rules_i / total_rules_i
CI_i = (0.7 * VS_i) + (0.3 * SV_i)
```
VS constants (current):
- Input 1 LinkedIn: 1.0
- Input 2 Resume: 0.9
- Input 3 Education: 0.9
- Input 4 Engagement: 0.7
- Input 5 Goals: 0.5 (stored only for now)
- Input 6 Platform (for pillar 11 placeholder): configurable (default 1.0)
## 7.2 Rule Scoring Contract
Every rule returns:
```json
{
"present": true,
"included_in_pillar_average": true,
"score": 75.0,
"raw": "source value used for this rule"
}
```
Missing data behavior (confirmed):
- If the input data for a rule is not available, return:
- `present=false`
- `score=0`
- `included_in_pillar_average=false`
- Missing rules do not penalize `pillar_score` directly, but they reduce `SV_i` and therefore `CI_i`.
## 7.3 Pillar Score
```
pillar_score = average(score of rules where included_in_pillar_average=true)
```
If no rules are included in the pillar average, the pillar is inactive unless configured as always-on placeholder.
## 7.4 Pillar CI (confirmed logic)
```
pillar_ci = sum(weight_i * CI_i)
weight_i = rules_from_input_i_in_pillar / total_rules_in_pillar
```
## 7.5 Pillar Contribution
```
contribution = pillar_score * pillar_weight * pillar_ci
```
## 7.6 Final Q-Score
```
Q = sum(contributions_of_active_pillars) / sum(active_pillar_weights)
```
Notes:
- no tier assignment in this release
- no percentile requirement in this release
---
## 8) Pillars and Rules Handling
Pillars locked for Saturday release (from `growqr/Q-Score_Service.md`):
- Pillar 01 Presence & Profile (20.0%)
- Pillar 02 Learning & Credentials (19.3%)
- Pillar 05 Engagement & Consistency (3.3%)
- Pillar 06 Communication Signals (4.0%)
- Pillar 11 Recognition & Rewards (0.9%)
Initial (day-1) score computations are expected to activate pillars 01, 02, 06, 11 if those signals are ingested.
Engagement pillar (05) is not required for day-1 and becomes active only when engagement signals are later ingested.
Important current behavior choices:
- Goals input is persisted but not used in score math right now.
- Engagement signal IDs are part of the formula registry, but are not expected to be present on day-1.
- Platform pillar (11) uses 3 onboarding achievements; scoring/points mapping is an open item to confirm.
Config examples:
- `P11_ACHIEVEMENT_COUNT=3`
- `P11_ACHIEVEMENT_SCORE_DEFAULT=100`
---
## 9) Persistence Design
Migration approach:
- Use Alembic migrations for all schema changes (job-service currently uses `metadata.create_all`, but Q-Score should be migration-driven).
## 9.1 `signal_ledger` (append-only, versioned history)
- `seq` bigserial pk
- `id` uuid unique
- `org_id` text not null
- `user_id` uuid not null
- `profession` text null
- `signal_id` text not null
- `source` text null
- `score` numeric(5,2) not null
- `raw` jsonb null
- `occurred_at` timestamptz null
- `formula_version` text not null
- `created_at` timestamptz not null
Indexes:
- `(org_id, user_id, created_at desc)`
- `(org_id, user_id, signal_id, created_at desc)`
## 9.2 `user_signal_latest` (materialized latest state)
- `org_id` text not null
- `user_id` uuid not null
- `signal_id` text not null
- `source` text null
- `score` numeric(5,2) not null
- `raw` jsonb null
- `last_occurred_at` timestamptz null
- `last_seen_at` timestamptz not null
- `formula_version` text not null
Primary key / unique:
- `(org_id, user_id, signal_id)`
## 9.3 `user_profile` (formula resolution)
- `org_id` text not null
- `user_id` uuid not null
- `profession` text not null
- `formula_version_override` text null
- `updated_at` timestamptz not null
Primary key / unique:
- `(org_id, user_id)`
## 9.4 `formula_definitions` (team-managed formulas)
- `org_id` text not null
- `profession` text not null
- `version` text not null
- `active` boolean not null
- `formula_json` jsonb not null
- `created_at` timestamptz not null
- `updated_at` timestamptz not null
Primary key / unique:
- `(org_id, profession, version)`
## 9.5 `user_dirty` (compute scheduling helper)
- `org_id` text not null
- `user_id` uuid not null
- `last_signal_seq` bigint not null
- `last_computed_seq` bigint null
- `next_compute_at` timestamptz null
- `last_published_at` timestamptz null
Primary key / unique:
- `(org_id, user_id)`
## 9.6 `qscore_runs` (append-only, versioned outputs)
- `id` uuid pk
- `org_id` text not null
- `user_id` uuid not null
- `profession` text not null
- `q_score` numeric(5,2) not null
- `breakdown` jsonb not null
- `formula_version` text not null
- `formula_id` text not null
- `ledger_seq_from` bigint null
- `ledger_seq_to` bigint null
- `created_at` timestamptz not null
Indexes:
- `qscore_runs(org_id, user_id, created_at desc)`
- `user_signal_latest(org_id, user_id)`
- `signal_ledger(org_id, user_id, created_at desc)`
---
## 10) Batch Recompute
Compute orchestration (MVP):
1) Live pacer (primary):
- worker updates `user_dirty.last_signal_seq` on every ingested ledger event
- worker sets `user_dirty.next_compute_at` using debounce logic
- pacer loop selects users whose `next_compute_at <= now` (recency-first)
- pacer loop must also ensure progress on older dirty users under sustained load (avoid starvation)
- compute uses `user_signal_latest`
- write `qscore_runs` + publish to `qscore.score_updates`
- update `user_dirty.last_computed_seq` + `last_published_at`
2) Periodic sweep (backlog safety):
- every `BATCH_INTERVAL_SECONDS` (default: 300), select users where `last_signal_seq > last_computed_seq`
- compute and publish
Freshness goal:
- cap staleness with `MAX_STALENESS_MS` (default: 10000)
Post-Saturday enhancements:
- selects users whose signals changed
- computes Q-Score in bulk
- writes new `qscore_runs`
Implementation note (Saturday):
- simplest is a second process/container that runs a loop (sleep -> check dirty -> compute) using the same codebase.
- we can also run it as a background task in the API process, but a separate worker is cleaner for production.
---
## 11) Codebase Layout
Proposed project path: `growqr/qscore-service/`
Reference scaffold (UV + FastAPI, job-service-like layout): `growqr/plans/qscore-service-uv-scaffold.md`
```
app/
main.py
api/
signals.py
qscore.py
registry.py
formulas.py
health.py
core/
config.py
logging.py
db/
session.py
models.py
repositories/
scoring/
engine/
loader.py
evaluator.py
breakdown.py
formula/
v1/
formula.json
worker/
stream_consumer.py
pacer.py
sweep.py
alembic/
docker-compose.yml
Dockerfile
README.md
```
---
## 12) Configuration (env vars)
Required:
- `DATABASE_URL`
Pub/Sub:
- `REDIS_URL`
- `SIGNAL_STREAM=qscore.signal_events`
- `QSCORE_UPDATE_STREAM=qscore.score_updates`
- `SIGNAL_CONSUMER_GROUP=qscore_engine`
- `SIGNAL_CONSUMER_NAME` (unique per worker instance)
Scoring/behavior:
- `FORMULA_VERSION=v1`
- `FORMULA_STORE=filesystem|db` (default: filesystem for local)
- `FORMULA_DIR=./scoring/formula` (used when FORMULA_STORE=filesystem)
- `BATCH_INTERVAL_SECONDS=300`
- `LIVE_DEBOUNCE_MS=750`
- `MAX_STALENESS_MS=10000`
- `MIN_PUBLISH_INTERVAL_MS=1500`
- `SCORE_CHANGE_EPSILON=0.01`
- `RAW_METADATA_MAX_BYTES=65536`
- `QSCORE_LATEST_TTL_SECONDS=86400`
- `P11_ACHIEVEMENT_COUNT=3`
- `P11_ACHIEVEMENT_SCORE_DEFAULT=100`
- optional VS overrides (`VS_INPUT_1`, etc.)
Ops:
- `LOG_LEVEL`
- `ENV`
---
## 13) Non-Functional Requirements
- API endpoints should be fast (target: < 300ms local for ingest/reads).
- Q-Score compute should remain under 5 seconds for a single user.
- No external network calls during Q-Score calculation (DB-only).
- Deterministic scoring logic for same stored inputs.
- Full explainability payload stored and retrievable.
---
## 14) Test Strategy
Unit tests:
- CI/SV formulas
- pillar CI weighted-average formula
- rule scoring edge cases per input
- final score active-weight denominator behavior
- formula.json schema validation and hot reload swap rules
- signal check endpoint validation rules
Integration tests:
- ingest signals -> compute qscore -> read latest
- ingest partial signals -> compute qscore (missing rules excluded from pillar avg; still impacts CI via SV)
- scheduler processes dirty users and updates `qscore_runs`
- stream consumer ingests signals and publishes score updates
- per-profession formula selection: same signals yield different Q when profession differs
- org_id isolation: signals from org A do not affect org B
Contract tests:
- validate signal ingest payload shape and `signal_id` naming conventions
Performance checks:
- ingest/read endpoints stay fast; compute remains under target runtime
---
## 15) Delivery Plan (Wed to Sat)
## Wednesday
- finalize spec mapping in code constants
- scaffold service, DB models, migrations, compose
- implement baseline scoring engine and response schema
- implement signals ingest contract + persistence
## Thursday
- implement `/v1/qscore/compute`
- implement `/v1/qscore/{user_id}` read
- implement `/v1/signals/check` and `/v1/registry/signals`
- add Redis streams to docker-compose and implement stream publish/consume
## Friday
- complete full rule-level breakdown output
- implement `/v1/signals/{user_id}` read
- implement batch scheduler loop (every 5 minutes, configurable)
- publish score update events on recompute
- write tests and fix gaps
## Saturday (buffer + integration)
- integration fixes with upstream callers
- perf pass and hardening
- docs and handoff
---
## 16) Meeting Walkthrough Script (for team confirmation)
Use this sequence in the call:
1. **Goal**: one explainable Q-Score service, ready by Saturday.
2. **Scope**: live signal stream ingest + compute Q-Score + publish live score updates + read endpoints.
3. **Decisions locked**:
- no tiers now
- this service only computes Q (no rule processing)
- full breakdown response required
- upstream services produce scored signals; this service only computes Q
4. **Math**: explain CI per input, weighted pillar CI, final active-weight normalization.
5. **Data flow**: agent publishes signal events to the input stream; engine consumes and publishes Q-Score update events.
6. **Future-safe design**: formula versioning + ledger history + scalable micro-batching.
7. **Timeline**: Wed/Thu/Fri/Sat milestones.
8. **Sign-off checklist** (below).
---
## 17) Sign-off Checklist
Please confirm in meeting:
- [ ] Endpoint contracts are approved.
- [ ] Rule and pillar mapping in `Q-Score_Service.md` is final for this sprint.
- [ ] Pillar 11 placeholder scoring is acceptable for MVP.
- [ ] Pillar 11 achievements/points mapping confirmed (open item for tonight).
- [ ] Goals stored-only behavior is approved.
- [ ] No-tier response format is approved.
- [ ] Signal ingest contract is approved (signal_id naming + score semantics).
- [ ] Signal check contract is approved (validation rules + unknown-signal behavior).
- [ ] Registry exposure scope approved (sanitized signals list vs full formula exposure).
- [ ] Multi-tenancy decision: include `org_id` now or defer.
---
## 18) Risks and Mitigations
1. **Spec ambiguity in pillar/rule mapping**
Mitigation: freeze a code-side config map and share before implementation lock.
2. **Upstream signal contract churn**
Mitigation: define stable `signal_id` registry and allow unknown signals to be stored but ignored by formula v1.
3. **Formula evolution complexity**
Mitigation: version the formula (`FORMULA_VERSION`) and make formula definitions config-driven.
---
## 19) Final Delivery Artifacts
By handoff, we will provide:
- running service via docker compose
- API endpoints documented
- DB migrations
- rule/pillar scoring engine
- explainable read response
- operational README for local + staging setup
---
This document is intended to be the single source of implementation alignment for the current sprint.

View File

@@ -0,0 +1,179 @@
# GrowQR Q-Score Engine - Meeting Brief (Top-Down)
Prepared for: Team alignment meeting
## 1) What We Are Building (Conceptual)
The Q-Score service is a dedicated "scoring engine" with live pub/sub feeds.
- Other services (agents) compute individual signals (rule outputs) from raw data.
- Example producers: social branding/LinkedIn agent, resume analyzer, education verifier, engagement logger, etc.
- The Q-Score engine does NOT scrape, parse, or analyze raw inputs.
- The Q-Score engine owns the formula (the "secret sauce") that converts signals into:
- pillar scores and contributions
- a final Q-Score
- a fully explainable breakdown that can be shown in the UI
Live communication requirement:
- The orchestrator agent publishes a continuous stream of signals.
- The Q-Score engine publishes a continuous stream of score updates.
- The agent subscribes to score updates so it can react instantly.
Practical meaning:
- Every microservice can remain "agent-owned" (each owns its own processing).
- Q-Score remains the shared engine that only aggregates and scores.
Agent "latest value" access without APIs:
- In addition to consuming the update stream, the engine writes `qscore:latest:{org_id}:{user_id}` in Redis.
- Agent can read that key to recover the last known score after restart.
In short:
"Producers compute signals. Q-Score engine aggregates and scores."
## 2) How We Implement It (Service Responsibilities)
The service has three core responsibilities:
1) Accept signals from producers and store them (with history).
2) Resolve the correct formula for the user (org + profession).
3) Compute Q-Score using that formula.
4) Publish score updates when the computed score changes.
5) Serve explainable outputs (rules + pillars + math) to the frontend/clients.
We keep the implementation modular so we can scale from today's ~44 rules to hundreds of signals and multiple formula versions.
## 3) How Rules, Pillars, and the Formula Work
### 3.1 Signals and Rules
- A "rule" in v1 is effectively a named slot that expects a processed signal.
- Each signal arrives already normalized to a `score` in `0..100`.
- Producers send only what they have; missing signals are interpreted as missing at compute time.
### 3.2 Inputs and CI (Confidence/Completeness)
We group rules into inputs (LinkedIn, Resume, Education, Engagement, Goals, Platform). Each input has:
- VS (verification score): fixed constant per input (from the current spec)
- SV (signal volume): how complete the input is based on which rules have signals
CI per input:
`CI = (0.7 * VS) + (0.3 * SV)`
Important behavior (agreed):
- If a signal is missing, it does NOT reduce the pillar average directly.
- Missing signals DO reduce SV, which reduces CI (so completeness still matters).
### 3.3 Pillars
- A pillar is a weighted group of rules.
- Pillar score: average of rule scores that are present (missing rules are excluded from the average).
Pillar CI (agreed): weighted average of input CIs contributing to the pillar.
- weights are based on "data points" = number of rules from each input inside that pillar.
### 3.4 Final Q-Score
- Each pillar contributes:
- `contribution = pillar_score * pillar_weight * pillar_ci`
- Final Q-Score is normalized by active pillar weights:
- `Q = sum(contributions) / sum(active_weights)`
## 4) The API Surface (How Teams Use the Engine)
Producers (upstream services):
1) Discover accepted signal IDs
- `GET /v1/registry/signals`
- returns a sanitized list of accepted `signal_id`s + basic metadata
Multi-tenant + profession aware:
- Requests/streams are keyed by `org_id`.
- Each user has a `profession`, which selects the active formula.
2) Validate a signal payload (fire-and-forget safety)
- `POST /v1/signals/check`
- input: `{ user_id, signal_id, score, raw? }`
- output: `{ valid, errors[], warnings[] }`
3) Ingest signals
- `POST /v1/signals/ingest`
- input: `{ user_id, source, occurred_at?, signals:[{signal_id, score, raw?}] }`
Streaming (preferred integration):
- Agent publishes signal events to the input stream (same shape as ingest).
- Agent subscribes to the output stream to receive Q-Score updates instantly.
Output updates include the full explainability breakdown so the agent/UI can render without extra RPC.
Consumers (frontend / read clients):
4) Compute now (manual trigger)
- `POST /v1/qscore/compute` with `{ user_id }`
5) Read latest score (full explainability)
- `GET /v1/qscore/{user_id}`
6) Read latest signals (debug + transparency)
- `GET /v1/signals/{user_id}`
## 5) Dataflow and Storage (Ledger + Latest + Outputs)
We store data in a way that preserves history AND keeps compute fast.
1) Append-only ledger (history)
- Every signal update is written to `signal_ledger`.
- This provides a timeline of how the user evolved.
2) Latest materialized state (fast compute)
- For each `(user_id, signal_id)` we keep the latest entry in `user_signal_latest`.
- Q-score compute reads from `user_signal_latest` (not from the full ledger).
3) Q-score outputs are versioned
- Every compute produces a new row in `qscore_runs` (append-only).
- This lets us track how computed outputs evolve over time.
4) Scheduler orchestration (batch)
- A small scheduler runs every `BATCH_INTERVAL_SECONDS` (default 300).
- It recomputes only users whose signals changed since the last compute.
- This is the path to scalable batch processing (intraday/hourly) without real-time pressure.
5) Live update loop (pub/sub)
- The engine consumes signal events continuously.
- The engine recomputes quickly (micro-batched / debounced).
- When the score changes, the engine publishes a score update event.
## 6) Formula Storage and Hot Reload
- Formula definitions live in a committed JSON file (version controlled): `formula.json`.
- We can support v1/v2 side-by-side.
- We support a reload mechanism:
- `POST /v1/formula/reload` reloads JSON from disk and swaps it only if validation passes.
## 7) Saturday Scope (What Is "Done")
For Saturday, we aim to deliver:
- A working engine-only service (no upstream processing logic)
- v1 formula JSON for the current rules and pillars (from `Q-Score_Service.md`)
- The ingest/check/registry/compute/read endpoints
- Ledger + latest + qscore_runs persistence
- Scheduler running every 5 minutes (configurable) + live micro-batched updates
- Explainability payload that is UI-ready
## 8) Clarifications to Close in Meeting
These are the only remaining items that affect integration and long-term scaling:
1) Canonical `signal_id` naming convention (and who owns the list going forward)
2) What raw metadata we store in the ledger (and size/PII limits)
3) Registry exposure scope:
- sanitized signals list only (recommended)
- or full formula exposure
4) Multi-tenancy decision:
- include `org_id` now (default "growqr")
- or defer until the first B2B client
5) Pillar 11 achievements: exact mapping of the 3 achievements to scores/points

View File

@@ -0,0 +1,75 @@
**Q-SCORE SERVICE \- DEVELOPER HANDOFF SPECIFICATION**
FEBRUARY 28TH LAUNCH | Minimal Viable Product | From: Katie | To: Rahul (Developer)
1\. THE 5 KPI (Current Release Only)
| Input \# | KPI Name | Data Source | VS Score | What to Extract |
| :---- | :---- | :---- | :---- | :---- |
| **1** | LinkedIn Profile | LinkedIn API (OAuth) | 1.0 | Connections, skills, endorsements, experience, headline, summary, photo |
| **2** | Resume/CV Upload | File Upload \+ GPT-4 | 0.9 | ATS score, keywords, projects, grammar, achievements, years exp |
| **3** | Education Docs | Document Upload | 0.9 | Institution name, degree, GPA, major, graduation year, verification |
| **4** | Engagement Activity | Backend Tracking | 0.7 | Login frequency, streaks, session time, features used, trends |
| **5** | Goals & Self-Assessment | User Form | 0.5 | Career goals, timeline, urgency, work preferences, target role |
**2\. RULES & CALCULATIONS (Grouped by Input Source)**
| KPI 1: LINKEDIN (11 rules) • Account connected: Binary (0 or 100\) • Profile photo: Binary (0 or 100\) • Headline quality: Length \+ keywords (0-100) • Summary complete: % filled (0-100) • Experience detail: Entries × detail (0-100) • Skills listed: 0=0, 5=50, 10+=100 • Endorsements: 0=0, 10=50, 50+=100 • Recommendations: 0=0, 3=50, 10+=100 • Connections: 0-50=20, 51-200=50, 201-500=75, 500+=100 • Post engagement (90d): (Likes+comments+shares)/posts • Education listed: Binary (0 or 100\) KPI 2: RESUME (15 rules) • Resume uploaded: Binary (0 or 100\) • ATS compatibility: GPT-4 scan (0-100) • Keyword relevance: Match to role (0-100) • Quantified achievements: Count metrics (0-100) • Grammar & clarity: AI analysis (0-100) • Format & structure: Sections/hierarchy (0-100) • Contact info: Email+phone+LinkedIn (0-100) • Page count: 1-2 pages=100, 3+=50 • Technical keywords: Count (0-100) • Project count: 0=0, 2=50, 3=75, 5+=100 • Project complexity: Tech stack × impact (0-100) • Years experience: 0=0, 1=40, 2=70, 3+=100 • Leadership indicators: Led/managed keywords • Impact statements: Increased/reduced verbs • Education section: Degree+institution+year KPI 3: EDUCATION (4 rules) • Documents uploaded: Binary (0 or 100\) • Institution tier: IIT/IIM=100, NIT=80, Tier2=60, Tier3=40 • Degree relevance: Match to career path (0-100) • GPA/percentage: Normalized (0-100) | KPI 4: ENGAGEMENT (8 rules) • Login frequency: Logins per week (0-7 scale) • Session duration avg: Minutes per session • Features used: Count of different features • Current streak: Consecutive days active • Longest streak: Historical max streak • Streak recovery: Ability to resume streaks • 30-day trend: Activity increase/decrease % • 90-day trend: Long-term activity pattern KPI 5: GOALS (6 rules) • Goals set: Binary \+ count • Goal clarity: Specific=100, Vague=50 • Timeline urgency: Immediate=100, Long-term=50 • Work preferences: Remote/hybrid/office INPUT6: |
| :---- | :---- |
**3\. KPI WEIGHTAGES (11 Pillars \- Must Total 100%)**
| Pillar | | Primary Inputs Used | Example Calculation |
| :---- | :---- | :---- | :---- |
| **01\. Presence & Profile** | | KPI 1, 2 | LinkedIn(11 rules) \+ Resume(15) |
| **02\. Learning & Credentials\*** | | KPI 3 | Education(4) |
| | | | |
| | | | |
| **05\. Engagement & Consistency** | | KPI 4 | All 8 engagement rules → Avg → Pillar Score |
| **06\. Communication Signals** | | KPI 1, 2 | LinkedIn summary \+ Resume grammar → Avg |
| | | | |
| | | | |
| | | | |
| | | | |
| **11\. Recognition & Rewards** | | Platform (Input 6\) | Badges \+ Points → Simple scoring \[BASIC\] |
\*the educations needs to be validated
| Input \# | KPI Name | Student Weightage & Qs it gives | Prof-Technical Weightage & Qs it gives | Prof-Creative Weightage & Qs it gives | Prof-Sales/BD Weightage & Qs it gives | Prof-Leadership Weightage & Qs it gives | Prof-Marketing Weightage & Qs it gives | Prof-Entrepreneur Weightage & Qs it gives |
| :---- | :---- | :---- | :---- | :---- | :---- | :---- | :---- | :---- |
| **1** | LinkedIn Profile | 2.84, SQ, CQm, NQ, CuQ, | 2.15, SQ, CQm, NQ, CuQ, RQx | 2.58, SQ, CQm, NQ, CuQ | 3.49, SQ, CQm, NQ, CuQ, RQx | 3.34, SQ, CQm, NQ, CuQ, RQx | 2.96, SQ, CQm, NQ, CuQ | 2.05, SQ, CQm, NQ, CuQ |
| **2** | Resume/CV Upload | 3.78, XQ, CQm, VQ | 3.01, XQ, CQm, VQ | 3.01, XQ, CQm, VQ | 3.1, XQ, CQm, VQ, RQx | 2.92, XQ, CQm, VQ, RQx | 2.96, XQ, CQm, VQ | 2.05, XQ, CQm, VQ |
| **3** | Education Docs | 3.78 | 2.58, DQm | 2.58 | 1.94, RQx | 2.5, RQx | 2.11 | 1.37 |
| **4** | Engagement Activity | 4.25, XQ, GQ, DQ | 3.44, XQ, GQ, DQ | 3.44, XQ, GQ, DQ | 3.1, XQ, GQ, DQ | 2.92, XQ, GQ, DQ | 3.37, XQ, GQ, DQ | 2.4, XQ, GQ, DQ |
| **5** | Goals & Self-Assessment | 3.5, GQ, VQ, DQ | 3.25, GQ, VQ, DQ | 3.5, GQ, VQ, DQ | 6, GQ, VQ, DQ | 4.25, GQ, VQ, DQ | 4, GQ, VQ, DQ | 7.5, GQ, VQ, DQ |
| **6\.** | Cover Letter | 1.89, CQm,VQ | 1.29, CQm,VQ | 1.72, CQm,VQ | 1.94, CQm,VQ, InQ | 1.67, CQm,VQ, InQ | 1.69, CQm,VQ | 1.03, CQm,VQ |
**SQ- Social Quotient, XQ- Execution Quotient, CQm- Communication Quotient, VQ- Vision Quotient, DQ- Drive Quotient,**
**GQ- Growth Quotient , RQx- Reputation Quotient ,DQM- Domain Quotient**
**4\. CORE ALGORITHM (Step-by-Step Implementation)**
| STEP 1: Calculate CI Formula: CI \= (0.7 × VS) \+ (0.3 × SV) Where: VS \= Verification Score Input 1 (LinkedIn) \= 1.0 Input 2 (Resume) \= 0.9 Input 3 (Education) \= 0.9 Input 4 (Engagement) \= 0.7 Input 5 (Goals) \= 0.5 SV \= Signal Volume Count of rules with data Normalize to 0-1 scale Example: LinkedIn: VS=1.0, SV=0.9 CI \= (0.7×1.0)+(0.3×0.9) CI \= 0.97 | STEP 2: Pillar Scores Formula: Pillar \= Score × Weight × CI Process: 1\. For each pillar: Get all rules for that pillar Calculate avg score 2\. Apply formula: Contribution \= Score × Weight × CI Example (Pillar 01): LinkedIn score: 75/100 Weight: 20% \= 0.20 CI: 0.97 Contribution: 75 × 0.20 × 0.97 \= 14.55 Do this for all 11 pillars | STEP 3: Final Q-Score Formula: Q \= Σ(Pillars) / Σ(Weights) Process: 1\. Sum all pillar contributions 2\. Sum active weights (Exclude Pillars 03, 08, 09 if not enabled / no data) 3\. Divide: Q-Score \= Total / Active Weights Example: Total contributions: 50.20 Active weights: 0.752 (Excludes Pillar 03, 08, 09\) Q-Score: 50.20 / 0.752 \= 66.76 Output: • Q-Score: 67.85/100 • Tier: Job Ready • Percentile: Calculate rank |
| :---- | :---- | :---- |
**5\. SIGNALS MEASURED (What Each Input Captures)**
| Input | Signal Type | What It Tells Us |
| :---- | :---- | :---- |
| **1\. LinkedIn** | Professional Network | |
| **2\. Resume** | Skills & Experience | |
| **3\. Education** | Academic Foundation | |
| **4\. Engagement** | Commitment & Drive | |
| **5\. Goals** | Vision & Planning | |
**6\. ONBOARDING INTEGRATION (API Contract)**
| | Processing Logic: 1\. Receive onboarding data 2\. Validate all 5 inputs present 3\. Run all \~44 rules 4\. Calculate 11 pillar scores 5\. Apply weights & CI 6\. Generate Q-Score (0-100) 7\. Determine tier & percentile 8\. Store in database 9\. Return response Processing Time: \< 5 seconds |
| :---- | :---- |
**7\. MINIMAL REQUIREMENTS FOR FEB 28TH LAUNCH**
| MUST HAVE ✓ ✓ 5 input parameters working ✓ \~44 core rules implemented ✓ 11 pillar calculations ✓ CI formula working ✓ Q-Score calculation (0-100) ✓ Tier assignment (5 tiers) ✓ Onboarding endpoint ✓ Read endpoint ✓ Database persistence ✓ Basic error handling ✓ Returns score in | SHOULD HAVE \~ \~ Update endpoint (for future) \~ Admin interface skeleton \~ Percentile calculation \~ Score breakdown in response \~ Logging & monitoring \~ Basic validation \~ API documentation \~ Scalable architecture |
| :---- | :---- |
CRITICAL: Focus on the \~44 rules from 5 inputs. Get the calculation engine working. The onboarding endpoint must return accurate Q-Score. Everything else is Phase 2\.

View File

@@ -0,0 +1,789 @@
{
"_meta": {
"document": "GrowQR Social Branding API — LinkedIn Profile Fetch",
"version": "1.0",
"generated_from": "Live database record (2026-02-11T07:47:30Z)",
"base_url": "https://<your-domain>/api/v1/profiles",
"authentication": "Bearer <clerk_jwt_token> in Authorization header"
},
"endpoint": {
"method": "POST",
"path": "/api/v1/profiles/fetch-by-url",
"description": "Fetches full LinkedIn profile data by scraping the provided URL via two external APIs (Bright Data + Scrapetable), merges the results, stores in database, and returns the enriched profile.",
"headers": {
"Authorization": "Bearer <clerk_jwt_token>",
"Content-Type": "application/json"
}
},
"request": {
"linkedin_url": "https://www.linkedin.com/in/rahul2608/"
},
"data_extraction_pipeline": {
"_note": "This section documents HOW each field in the response is sourced and transformed. Understanding this pipeline confirms the response structure is correct.",
"step_1_parallel_fetch": {
"description": "Two external APIs are called concurrently via asyncio.gather()",
"source_a": {
"name": "Bright Data Web Scraper API",
"url": "https://api.brightdata.com/datasets/v3/scrape",
"provides": [
"experience",
"education",
"skills",
"certifications",
"languages",
"courses",
"projects",
"organizations",
"honors_awards",
"recommendations",
"activity",
"current_company",
"banner_image_url",
"industry",
"headline",
"summary",
"first_name",
"last_name",
"location",
"profile_picture_url",
"followers_count",
"connections_count"
],
"field_mapping": {
"raw → normalized": {
"name → first_name/last_name": "Split on first space, or use first_name/last_name directly",
"position|headline → headline": "Falls back to 'headline' if 'position' missing",
"about → summary": "Direct map",
"city|location → location": "Prefers 'city' field",
"avatar|profile_picture_url → profile_picture_url": "Prefers 'avatar'",
"banner_image|background_image → banner_image_url": "Prefers 'banner_image'",
"url|linkedin_url → public_profile_url": "Direct map",
"followers|followers_count → followers_count": "Prefers 'followers'",
"connections|connections_count → connections_count": "Prefers 'connections'",
"current_company.industry → industry": "Extracted from nested company object",
"current_company.link|url|linkedin_url → current_company.url": "Prefers 'link'",
"current_company.logo|logo_url → current_company.logo_url": "Prefers 'logo'",
"experience[].company_linkedin_url → experience[].company_url": "Renamed field",
"education[].title|school → education[].school": "Prefers 'title'",
"education[].start_year|start_date → education[].start_date": "Prefers 'start_year'",
"certifications[].title|name → certifications[].name": "Prefers 'title'",
"certifications[].subtitle|authority → certifications[].authority": "Prefers 'subtitle'",
"certifications[].meta → certifications[].start_date": "Parsed from 'Issued MMM YYYY'",
"skills[]: string|{name|skill} → skills[]: string": "Extracts name from object if needed",
"languages[].title|name → languages[].name": "Prefers 'title'",
"languages[].subtitle|proficiency → languages[].proficiency": "Prefers 'subtitle'",
"courses[].title → courses[].name": "Renamed",
"courses[].subtitle → courses[].number": "Renamed",
"organizations[].title → organizations[].name": "Renamed",
"organizations[].membership_type → organizations[].position": "Renamed",
"honors_and_awards[].publication → honors_awards[].issuer": "Renamed",
"activity[].link → activity[].url": "Renamed",
"activity[].interaction → activity[].type": "Renamed",
"activity[].reactions → activity[].likes": "Renamed",
"recommendations[]: string → {text, recommender_name}": "Parsed from 'Name \"text\"' format"
}
}
},
"source_b": {
"name": "Scrapetable API",
"url": "https://v3.scrapetable.com/linkedin/people",
"provides": [
"experience",
"education",
"skills",
"first_name",
"last_name",
"headline",
"summary",
"location",
"profile_picture_url",
"linkedin_id",
"followers_count",
"connections_count"
],
"field_mapping": {
"raw → normalized": {
"person.firstName → first_name": "Direct map",
"person.lastName → last_name": "Direct map",
"person.headline → headline": "Direct map",
"person.summary → summary": "Direct map",
"person.geoFull → location": "Full geo string",
"person.profilePicture → profile_picture_url": "CDN-hosted image URL",
"person.profileUrl → public_profile_url": "Direct map",
"person.linkedinId → linkedin_id": "Direct map",
"person.followers → followers_count": "Direct map",
"person.connections → connections_count": "Direct map",
"person.skills → skills": "Already a string array, used directly",
"person.positions[].companyName → experience[].company": "Renamed",
"person.positions[].startYear + startMonth → experience[].start_date": "Formatted as MM/YYYY",
"person.positions[].endYear + endMonth → experience[].end_date": "Formatted as MM/YYYY or 'Present'",
"person.positions[].companyId → experience[].company_url": "Constructed as linkedin.com/company/{id}",
"person.education[].schoolName → education[].school": "Renamed",
"person.education[].startYear → education[].start_date": "Year string only",
"person.education[].endYear → education[].end_date": "Year string only"
}
}
}
},
"step_2_merge_strategy": {
"description": "Fields are merged with priority rules — Scrapetable for structured data quality, Bright Data for breadth.",
"priority_rules": {
"experience": "Scrapetable first, Bright Data fallback",
"education": "Scrapetable first, Bright Data fallback",
"skills": "Scrapetable first, Bright Data fallback",
"headline": "Scrapetable first, Bright Data fallback",
"summary": "Longer of the two (more complete)",
"first_name": "Scrapetable first, Bright Data fallback",
"last_name": "Scrapetable first, Bright Data fallback",
"location": "Scrapetable first, Bright Data fallback",
"profile_picture_url": "Scrapetable first (higher quality CDN)",
"linkedin_id": "Scrapetable first, Bright Data fallback",
"followers_count": "Whichever has data",
"connections_count": "Whichever has data",
"industry": "Bright Data only",
"certifications": "Bright Data only",
"languages": "Bright Data only",
"courses": "Bright Data only",
"projects": "Bright Data only",
"organizations": "Bright Data only",
"honors_awards": "Bright Data only",
"recommendations": "Bright Data only",
"activity": "Bright Data only",
"current_company": "Bright Data only",
"banner_image_url": "Bright Data only"
}
},
"step_3_db_persistence": {
"description": "Merged data is written to linkedin_profiles table (PostgreSQL JSONB columns for arrays/objects, TEXT/VARCHAR for scalars). connection_status set to CONNECTED, last_synced_at set to now()."
},
"step_4_response_assembly": {
"description": "The _build_profile_detail_response() function reads the DB model and constructs LinkedInProfileDetailResponse Pydantic model, which is wrapped in FetchByUrlResponse."
}
},
"response": {
"success": true,
"message": "Profile fetched successfully",
"fetch_status": "completed",
"profile": {
"id": "70529a20-873d-4a6f-bc11-ab6bcec5b8b0",
"linkedin_id": "ACoAAB8LpMUB2XVVN-uGsshaioFR58XxqPmOwZM",
"first_name": "Rahul",
"last_name": "Gupta",
"headline": "Walmart Global Tech | MS in Computer Science",
"summary": "At Fleuxlabs, our team leverages artificial intelligence to transform user interaction with digital platforms, fostering a seamless fusion of human cognitive processes and technological innovation. Our solutions, powered by AI expertise, particularly in PyTorch and Jupyter, are designed to deliver intuitive experiences that resonate with our users.\n\nMy educational pursuits at San Diego State University in Computer Science are instrumental in shaping the strategic direction of Fleuxlabs. With a solid background in AI and deep learning, the insights gained from my studies are integral to the pioneering work we do, ensuring that our technological advancements continue to set industry standards.",
"industry": null,
"location": "United States",
"profile_picture_url": "https://scrapetable.b-cdn.net/linkedin-people/linkedin-profile-rahul2608-1770796033431.jpg",
"public_profile_url": "https://www.linkedin.com/in/rahul2608/",
"connection_status": "CONNECTED",
"connections_count": 500,
"followers_count": 623,
"last_synced_at": "2026-02-11T07:47:30.361228+00:00",
"created_at": "2026-02-11T07:47:10.284378+00:00",
"email": null,
"banner_image_url": "https://media.licdn.com/dms/image/v2/C5116AQGVMt-5-aC2TQ/profile-displaybackgroundimage-shrink_200_800/profile-displaybackgroundimage-shrink_200_800/0/1517506105412?e=2147483647&v=beta&t=YxKKlI8jdr7gzD3rg5c4GSwh9NZDr9yt2Y68CYG4wp4",
"current_company": {
"name": "Walmart Global Tech",
"industry": null,
"url": "https://www.linkedin.com/company/walmartglobaltech?trk=public_profile_topcard-current-company",
"logo_url": null
},
"experience": [
{
"title": "AI Engineer | ML Ops",
"company": "Walmart Global Tech",
"company_url": "https://www.linkedin.com/company/11174522",
"location": "Sunnyvale, California, United States",
"start_date": "06/2018",
"end_date": "06/2025",
"duration": null,
"is_current": false,
"description": null
},
{
"title": "Software Development Engineer II",
"company": "Walmart Global Tech",
"company_url": "https://www.linkedin.com/company/11174522",
"location": "Sunnyvale, California, United States",
"start_date": "06/2021",
"end_date": "08/2022",
"duration": null,
"is_current": false,
"description": null
},
{
"title": "Peer Mentor",
"company": "San Diego State University",
"company_url": "https://www.linkedin.com/company/6206",
"location": "International Student Centre, San Diego",
"start_date": "09/2016",
"end_date": "05/2018",
"duration": null,
"is_current": false,
"description": "As a student mentor, I worked with incoming international freshmen to help them adapt to a new culture and environment. I ensured that they were successful by guiding and counseling them on how to navigate their first semester at the university. I also made sure that they connected with the various resources available on campus."
},
{
"title": "Software Developer",
"company": "Cal Hacks",
"company_url": "https://www.linkedin.com/company/6430466",
"location": null,
"start_date": "10/2015",
"end_date": "10/2015",
"duration": null,
"is_current": false,
"description": "I developed a virtual reality game using the Myo motion detector, which allowed users to virtually interact with objects and characters in the game."
}
],
"education": [
{
"school": "San Diego State University",
"degree": "Master of Science - MS",
"field_of_study": "Computer Science",
"start_date": "2022",
"end_date": "2024",
"school_url": null,
"description": null,
"activities": null
},
{
"school": "San Diego State University-California State University",
"degree": "Bachelor of Science (B.S.)",
"field_of_study": "Computer Science",
"start_date": "2014",
"end_date": "2018",
"school_url": null,
"description": null,
"activities": null
}
],
"skills": [
"PyTorch",
"Jupyter",
"Artificial Intelligence (AI)",
"Vector Databases",
"Large Language Models (LLM)",
"Next.js",
"Machine Learning",
"Java",
"C",
"C++",
"Bash",
"Data Structures",
"Computer Architecture",
"Lua",
"Haskell",
"Unix",
"SQL",
"Object-Oriented Programming (OOP)",
"Python",
"JavaScript"
],
"certifications": [
{
"name": "Oracle Certified Professional, Java SE 8 Programmer II",
"issuing_organization": null,
"authority": "Oracle",
"issue_date": null,
"credential_url": null,
"license_number": null,
"url": "https://www.youracclaim.com/badges/95333ac3-13e2-422f-a75c-9d9ab8fc1d7b/linked_in_profile?trk=public_profile_see-credential",
"start_date": "Apr 2019",
"end_date": null
},
{
"name": "Oracle Certified Associate, Java SE 8 Programmer",
"issuing_organization": null,
"authority": "Oracle",
"issue_date": null,
"credential_url": null,
"license_number": null,
"url": "https://www.youracclaim.com/badges/a8858bd2-295e-4590-ad76-0cb1bd9b83e7/linked_in_profile?trk=public_profile_see-credential",
"start_date": "Feb 2019",
"end_date": null
}
],
"languages": [
{
"name": "English",
"proficiency": "Full professional proficiency"
},
{
"name": "Hindi",
"proficiency": "Native or bilingual proficiency"
}
],
"courses": [
{
"name": "Assembly Language and Machine Learning",
"number": "237",
"associated_with": null
},
{
"name": "Computer Architecture",
"number": "370",
"associated_with": null
},
{
"name": "Intermediate Java Programming",
"number": "108",
"associated_with": null
},
{
"name": "Programming Languages",
"number": "320",
"associated_with": null
},
{
"name": "Statistical Methods",
"number": "350A",
"associated_with": null
}
],
"projects": [
{
"name": "Fleuxlabs",
"url": null,
"start_date": "Aug 2022",
"end_date": null,
"description": null,
"associated_with": null
}
],
"organizations": [
{
"name": "Golden Key International Honour Society",
"position": "Member",
"start_date": "Sep 2016",
"end_date": "Present",
"description": "One of the most prestigious honour society at SDSU which only accepts students who are in the top 15 percent of their class.The purpose of the society is to recognize and encourage scholastic achievement and excellence in all undergraduate fields of study, to unite with collegiate faculties and administrators in developing and maintaining high educational standards, to provide scholarships to outstanding initiates, and to foster altruistic conduct through voluntary service."
},
{
"name": "Model United Nations (SDSU)",
"position": "Member",
"start_date": "Sep 2016",
"end_date": "Present",
"description": "This platform gave me a chance talk about issues that concern our entire humanity, and gain leadership skills. The chance to attend conferences in different campuses not only helped me inculcate people skills but also listening to my fellows made me realise that there are so many things that we can learn from each other."
},
{
"name": "Phi Eta Sigma National Honor Society, Inc.",
"position": "Member",
"start_date": "Sep 2015",
"end_date": "Present",
"description": "Phi Eta Sigma is an all-disciplines freshman national honor society established in 1923. The purpose of Phi Eta Sigma is to encourage and reward high scholastic achievement among freshmen students in institutions of higher education. This society definitely helped to evolve my character and care for my fellow beings. Now I truly believe that it is essential to use our academic prowess not only for our personal benefits but rather for the betterment of entire mankind."
},
{
"name": "The National Society of Collegiate Scholars",
"position": "Member",
"start_date": "Sep 2015",
"end_date": "Present",
"description": "The National Society of Collegiate Scholars (NSCS) is an honors organization that recognizes and elevates high achievers."
}
],
"honors_awards": [
{
"title": "Dean's List Awardee",
"issuer": "College of Sciences, San Diego State University",
"date": "2016-09-01T00:00:00.000Z",
"description": "Spring 2016",
"associated_with": null
},
{
"title": "Dean's List Awardee",
"issuer": "College of Sciences, San Diego State University",
"date": "2016-01-01T00:00:00.000Z",
"description": "Fall 2015",
"associated_with": null
},
{
"title": "Dean's List Awardee",
"issuer": "College of Sciences, San Diego State University",
"date": "2015-09-01T00:00:00.000Z",
"description": "Spring 2015",
"associated_with": null
},
{
"title": "Dean's List Awardee",
"issuer": "College of Sciences, San Diego State University",
"date": "2015-01-01T00:00:00.000Z",
"description": "Fall 2014",
"associated_with": null
}
],
"recommendations": [
{
"recommender_name": null,
"recommender_title": null,
"relationship": null,
"text": "Parvesh Koya “I have known Rahul from our first day at San Diego State University. From the first day I met him, it was very clear that he was committed, motivated, and profoundly intelligent. I have had the opportunity of working together with him on many projects and have seen first hand his leadership capabilities and his attention to detail. His leadership qualities combined with his in-depth knowledge of the various fields of computer science, Rahul is a priceless asset to any team. ”",
"date": null
}
],
"activity": [
{
"type": "Liked by Rahul Gupta",
"title": "I hosted the China-India Youth Dialogue on February 25th alongside Su Chen from the Political Department of the Embassy of the People's Republic of…",
"url": "https://www.linkedin.com/posts/amulyagupta1_bilateralties-globalcitizenship-collaborationbeyondborder-activity-7300845318680522752-UTAz",
"date": null,
"likes": null,
"comments": null
},
{
"type": "Liked by Rahul Gupta",
"title": "Are we all just performing? In a world where every moment is curated and shared, the line between authenticity and performance is blurrier than ever.…",
"url": "https://www.linkedin.com/posts/akarshkain_modernhumanspodcast-opherbrayer-authenticity-activity-7298798754554355712-VMOe",
"date": null,
"likes": null,
"comments": null
},
{
"type": "Liked by Rahul Gupta",
"title": "Leadership Exodus: Founders, CEOs Who Quit Their Startups In 2024👇 One of the most common occurrences in the worlds third-largest startup…",
"url": "https://www.linkedin.com/posts/inc42_leadershipexodus-founderstories-indianstartups-activity-7278993255994683392-0hEZ",
"date": null,
"likes": null,
"comments": null
},
{
"type": "Liked by Rahul Gupta",
"title": "I am excited to share that I have graduated from San Diego State University with a Bachelor of Science in Computer Science, achieving the distinction…",
"url": "https://www.linkedin.com/posts/bennett-hilck-96080226a_i-am-excited-to-share-that-i-have-graduated-activity-7201032802018959360-8tg3",
"date": null,
"likes": null,
"comments": null
},
{
"type": "Liked by Rahul Gupta",
"title": "The Empire State Building is getting a fresh new look with new uniforms for its employees 🏙️ Designed by renowned fashion designer Peyman Umay…",
"url": "https://www.linkedin.com/posts/naumd_empirestatebuilding-peymanumay-workwear-activity-7026300330476802048-BI4q",
"date": null,
"likes": null,
"comments": null
},
{
"type": "Liked by Rahul Gupta",
"title": "💬 As someone who's had many conversations with founders lately, I've come up with a helpful list for anyone looking to improve their company's…",
"url": "https://www.linkedin.com/posts/kharitojulia_as-someone-whos-had-many-conversations-activity-7026301274086146048-jFiP",
"date": null,
"likes": null,
"comments": null
},
{
"type": "Liked by Rahul Gupta",
"title": "Just wanted to share my top three tools for staying organized and on top of both work and personal life! 💻📅 1⃣ Asana - a game-changer for project…",
"url": "https://www.linkedin.com/posts/kharitojulia_just-wanted-to-share-my-top-three-tools-for-activity-7025981147188789248-E0oc",
"date": null,
"likes": null,
"comments": null
},
{
"type": "Liked by Rahul Gupta",
"title": "⚠️ If you still think of your target audience as \"people of a certain age,\" you're missing out on an opportunity to connect with them. This might…",
"url": "https://www.linkedin.com/posts/kharitojulia_if-you-still-think-of-your-target-audience-activity-7025946215502536704-WiKR",
"date": null,
"likes": null,
"comments": null
},
{
"type": "Liked by Rahul Gupta",
"title": "Are you tired of posting on social media and not seeing the results you want? I know, it's frustrating when your hard work doesn't seem to be paying…",
"url": "https://www.linkedin.com/posts/kharitojulia_are-you-tired-of-posting-on-social-media-activity-7024181789279608832-DARV",
"date": null,
"likes": null,
"comments": null
},
{
"type": "Liked by Rahul Gupta",
"title": "Yes I'm still using the hypebeast stack core: - react - typescript - node.js - postgresql addons: - graphql -…",
"url": "https://www.linkedin.com/posts/benawad_coding-programming-softwareengineering-activity-6991436280869916673-a9l0",
"date": null,
"likes": null,
"comments": null
},
{
"type": "Liked by Rahul Gupta",
"title": "Did you know that 95% of total television coverage focuses on mens sports? Womens leagues are hardly the focus of mainstream media, nor are they…",
"url": "https://www.linkedin.com/posts/femalequotient_did-you-know-that-95-of-total-television-activity-6998073717616492544-m6rJ",
"date": null,
"likes": null,
"comments": null
},
{
"type": "Liked by Rahul Gupta",
"title": "Hi folks, wanted to inform everyone that I am one of the unfortunate 11000 people affected due to recent layoffs at Meta. My heart goes out to…",
"url": "https://www.linkedin.com/posts/neeraj-desh_opentowork-metalayoffs-h1bvisa-activity-6996348074730139648-h33E",
"date": null,
"likes": null,
"comments": null
},
{
"type": "Liked by Rahul Gupta",
"title": "The hardest part of being a software engineer is not getting fat eating all the free snacks #coding #programming #softwareengineering…",
"url": "https://www.linkedin.com/posts/benawad_coding-programming-softwareengineering-activity-6996576933727653888-CLVq",
"date": null,
"likes": null,
"comments": null
},
{
"type": "Liked by Rahul Gupta",
"title": "I think companies should own a bit of responsibility when treating international employees on Visa. Maybe work with Congress to give extra runway (6…",
"url": "https://www.linkedin.com/posts/7ankit_i-think-companies-should-own-a-bit-of-responsibility-activity-6994394684668198912-43Tv",
"date": null,
"likes": null,
"comments": null
}
]
}
},
"error_responses": {
"auth_missing": {
"status_code": 401,
"body": {
"detail": "Authentication required"
}
},
"invalid_url": {
"status_code": 400,
"body": {
"detail": "Invalid LinkedIn URL format. URL should be like: https://linkedin.com/in/username"
}
},
"both_sources_failed": {
"status_code": 200,
"body": {
"success": false,
"message": "Failed to fetch profile data from both sources. Please try again later.",
"profile": null,
"fetch_status": "failed"
}
}
},
"field_reference": {
"_note": "Complete field-level reference for every key in profile object",
"top_level_envelope": {
"success": {
"type": "boolean",
"values": [
true,
false
]
},
"message": {
"type": "string",
"example": "Profile fetched successfully"
},
"fetch_status": {
"type": "string",
"enum": [
"pending",
"fetching",
"completed",
"failed"
]
},
"profile": {
"type": "LinkedInProfileDetailResponse | null"
}
},
"profile_scalars": {
"id": {
"type": "uuid",
"source": "DB-generated"
},
"linkedin_id": {
"type": "string",
"source": "Scrapetable > Bright Data",
"example": "ACoAAB8LpMUB2XVVN-uGsshaioFR58XxqPmOwZM"
},
"first_name": {
"type": "string|null",
"source": "Scrapetable > Bright Data"
},
"last_name": {
"type": "string|null",
"source": "Scrapetable > Bright Data"
},
"headline": {
"type": "string|null",
"source": "Scrapetable > Bright Data",
"max_length": 500
},
"summary": {
"type": "string|null",
"source": "Longer of Scrapetable vs Bright Data"
},
"industry": {
"type": "string|null",
"source": "Bright Data only (from current_company)"
},
"location": {
"type": "string|null",
"source": "Scrapetable > Bright Data"
},
"profile_picture_url": {
"type": "string|null",
"source": "Scrapetable > Bright Data (Scrapetable preferred for CDN quality)"
},
"public_profile_url": {
"type": "string|null",
"source": "Input linkedin_url"
},
"connection_status": {
"type": "string",
"enum": [
"CONNECTED",
"DISCONNECTED"
]
},
"connections_count": {
"type": "integer|null",
"source": "Whichever source has data"
},
"followers_count": {
"type": "integer|null",
"source": "Whichever source has data"
},
"last_synced_at": {
"type": "ISO 8601 datetime|null",
"source": "Set on successful fetch"
},
"created_at": {
"type": "ISO 8601 datetime",
"source": "DB-generated on first insert"
},
"email": {
"type": "string|null",
"source": "Not populated by scraping"
},
"banner_image_url": {
"type": "string|null",
"source": "Bright Data only"
}
},
"profile_objects": {
"current_company": {
"type": "object|null",
"source": "Bright Data only",
"fields": {
"name": "string|null",
"industry": "string|null",
"url": "string|null — LinkedIn company page URL",
"logo_url": "string|null — Company logo image URL"
}
}
},
"profile_arrays": {
"experience[]": {
"source": "Scrapetable > Bright Data",
"fields": {
"title": "string|null — Job title",
"company": "string|null — Company name",
"company_url": "string|null — LinkedIn company page URL",
"location": "string|null — City, State, Country",
"start_date": "string|null — Format: MM/YYYY",
"end_date": "string|null — Format: MM/YYYY or 'Present'",
"duration": "string|null — e.g. '3 yrs 2 mos'",
"is_current": "boolean — true if no end_date",
"description": "string|null — Role description"
}
},
"education[]": {
"source": "Scrapetable > Bright Data",
"fields": {
"school": "string|null — Institution name",
"degree": "string|null — e.g. 'Master of Science - MS'",
"field_of_study": "string|null — e.g. 'Computer Science'",
"start_date": "string|null — Year only: 'YYYY'",
"end_date": "string|null — Year only: 'YYYY'",
"school_url": "string|null — LinkedIn school page URL",
"description": "string|null",
"activities": "string|null"
}
},
"skills[]": {
"source": "Scrapetable > Bright Data",
"type": "string[] — Flat array of skill name strings"
},
"certifications[]": {
"source": "Bright Data only",
"fields": {
"name": "string|null — Certification name",
"issuing_organization": "string|null",
"authority": "string|null — e.g. 'Oracle'",
"issue_date": "string|null",
"credential_url": "string|null",
"license_number": "string|null",
"url": "string|null — Credential verification URL",
"start_date": "string|null — e.g. 'Apr 2019'",
"end_date": "string|null"
}
},
"languages[]": {
"source": "Bright Data only",
"fields": {
"name": "string|null — e.g. 'English'",
"proficiency": "string|null — e.g. 'Full professional proficiency'"
}
},
"courses[]": {
"source": "Bright Data only",
"fields": {
"name": "string|null — Course name",
"number": "string|null — Course number e.g. '370'",
"associated_with": "string|null"
}
},
"projects[]": {
"source": "Bright Data only",
"fields": {
"name": "string|null — Project name",
"url": "string|null — Project URL",
"start_date": "string|null — e.g. 'Aug 2022'",
"end_date": "string|null",
"description": "string|null",
"associated_with": "string|null"
}
},
"organizations[]": {
"source": "Bright Data only",
"fields": {
"name": "string|null — Organization name",
"position": "string|null — e.g. 'Member'",
"start_date": "string|null — e.g. 'Sep 2016'",
"end_date": "string|null — e.g. 'Present'",
"description": "string|null"
}
},
"honors_awards[]": {
"source": "Bright Data only",
"fields": {
"title": "string|null — Award name",
"issuer": "string|null — Issuing organization",
"date": "string|null — ISO 8601 date or free text",
"description": "string|null",
"associated_with": "string|null"
}
},
"recommendations[]": {
"source": "Bright Data only",
"fields": {
"recommender_name": "string|null",
"recommender_title": "string|null",
"relationship": "string|null",
"text": "string|null — Full recommendation text",
"date": "string|null"
}
},
"activity[]": {
"source": "Bright Data only",
"fields": {
"type": "string|null — e.g. 'Liked by Rahul Gupta'",
"title": "string|null — Post preview text (truncated)",
"url": "string|null — LinkedIn post URL",
"date": "string|null",
"likes": "integer|null",
"comments": "integer|null"
}
}
}
}
}

187
qscore/docs/plan.md Normal file
View File

@@ -0,0 +1,187 @@
# Plan: Quotients Derived from Pillars/Rules (QScore Service)
## Branch
- Working branch: `feature/quotients-from-pillars`
- Base branch: `admin-ui`
## Goal
Add **quotient outputs** (e.g., SQ, XQ, CQm, VQ, DQ, GQ, RQx, DQm, etc.) to QScore outputs so frontend/consumers can show which quotients are available for a user and their computed values.
This must be derived from existing scoring context (signals -> rules -> pillars -> weights -> CI), not hardcoded per user.
Delivery scope includes **every output path**:
- API responses (`/v1/qscore/compute`, `/v1/qscore/{user_id}`)
- Redis score update stream (`qscore.score_updates`)
- Redis latest cache key (`qscore:latest:{org_id}:{user_id}`)
---
## What changed in product doc
From updated `docs/Q-Score_Service.md` table:
- Each KPI/input now includes associated quotient tags per profession.
- Example: LinkedIn input for student maps to `SQ, CQm, NQ, CuQ`, Resume maps to `XQ, CQm, VQ`, etc.
---
## Design proposal (quick, extensible)
### 1) Formula metadata extension
Add optional quotient tags to each input in formula JSON:
```json
"inputs": {
"linkedin": {
"vs": 1.0,
"label": "LinkedIn Profile",
"signal_ids": [...],
"quotients": ["SQ", "CQm", "NQ", "CuQ"]
}
}
```
Why input-level first:
- Doc table currently maps quotients at KPI/input level.
- Rules already map to inputs; pillars map to rules.
- We can derive rule/pillar quotient linkage without duplicating metadata everywhere.
### 2) Rule + pillar quotient attribution
- A rule inherits quotients from its input.
- A pillars quotient exposure = union of quotient tags from all rules in that pillar.
- For each quotient within a pillar, compute rule-share:
- `quotient_rule_share = rules_in_pillar_with_quotient / total_rules_in_pillar`
### 3) Quotient scoring math
Use same normalization pattern as Q-Score with pillar weights:
- `quotient_contribution += pillar.contribution * quotient_rule_share`
- `quotient_active_weight += pillar.weight * quotient_rule_share` (only active pillars)
- `quotient_score = quotient_contribution / quotient_active_weight` (if weight > 0 else 0)
This keeps quotient math aligned with existing pillar-weighted scoring.
### 4) API response changes
Add new top-level field in both compute/read responses:
```json
"quotients": {
"SQ": { "score": 71.2, "active": true, "contribution_sum": 21.34, "active_weight_sum": 0.299 },
"CQm": { ... }
}
```
Also include quotient details in breakdown for transparency:
```json
"breakdown": {
...,
"quotients": {
"SQ": {
"score": 71.2,
"contribution_sum": 21.34,
"active_weight_sum": 0.299,
"pillars": ["p01_presence_profile", "p06_communication_signals"]
}
}
}
```
### 5) Redis output contract changes (producer/consumer path)
Add quotient data to worker-published stream payload (`qscore.score_updates`) and latest cache key:
- Stream event (`publisher.py`) should include:
- `quotients` (JSON string)
- `breakdown` already includes `breakdown.quotients`
- Latest key (`qscore:latest:{org_id}:{user_id}`) should include:
- `quotients`
Example stream fields added:
```json
{
"q_score": "67.42",
"formula_version": "v1",
"quotients": "{\"SQ\":{\"score\":71.2,...}}",
"breakdown": "{\"inputs\":...,\"quotients\":...}"
}
```
---
## Files to update
### Scoring engine
- `app/scoring/engine/loader.py`
- extend `FormulaInput` with optional `quotients: list[str] = []`
- `app/scoring/engine/evaluator.py`
- compute quotient attribution + scores from pillar/rule structure
- include quotient results in `QScoreResult`
- `app/scoring/engine/breakdown.py`
- append `quotients` section to breakdown payload
### API contracts
- `app/api/schemas.py`
- add `quotients: dict[str, Any]` to:
- `QScoreComputeResponse`
- `QScoreReadResponse`
- `app/api/qscore.py`
- return new `quotients` in both compute/read paths
### Stream/cache contracts
- `app/worker/publisher.py`
- publish `quotients` in `qscore.score_updates` stream event
- include `quotients` in `qscore:latest:{org_id}:{user_id}` cache payload
- `app/worker/compute.py`
- pass computed `quotients` into publisher
### Formula data
- `app/scoring/formula/v1/*/formula.json`
- add `quotients` array to each input, profession-specific per updated doc table
### Docs
- `README.md`
- update endpoint contract examples with `quotients`
- `docs/Q-Score_Service.md`
- keep as source-of-truth reference (already updated by product)
### Tests
- `tests/unit/test_loader.py`
- validate formulas with new `quotients` field
- `tests/unit/test_evaluator.py`
- verify quotient score derivation and deterministic behavior
- `tests/unit/test_breakdown.py`
- verify `breakdown.quotients` exists and is JSON-serializable
- `tests/unit` (new publisher-focused test or extend existing)
- verify stream payload includes `quotients` and latest cache payload includes `quotients`
---
## Backward compatibility
- Make `quotients` optional in formula schema, default `[]`.
- Existing formulas without quotient metadata still load.
- In that case, API returns empty `quotients` object.
---
## Implementation order (fast path)
1. Extend loader schema and defaults.
2. Add quotient computation in evaluator.
3. Add breakdown + API response fields.
4. Add Redis stream/latest payload quotient fields.
5. Patch all v1 formula files with quotient tags.
6. Update tests and docs.
---
## Open items to confirm before coding
1. **Output shape preference**: top-level `quotients` only, or both top-level and `breakdown.quotients`? (recommended: both)
2. **Code names**: keep exact short codes from doc (`SQ`, `CQm`, `RQx`, etc.) as API keys? (recommended: yes)
3. **Undefined codes in legend** (e.g., `NQ`, `CuQ`, `InQ`) should we still pass through as-is from doc? (recommended: yes, pass-through)
---
## Acceptance criteria
- `POST /v1/qscore/compute` and `GET /v1/qscore/{user_id}` return non-empty `quotients` when mapped signals exist.
- `qscore.score_updates` stream events include `quotients`.
- `qscore:latest:{org_id}:{user_id}` cache payload includes `quotients`.
- Quotient values change when pillar/rule scores change.
- Existing Q-Score output remains unchanged.
- Formula files load successfully with new metadata.

View File

@@ -0,0 +1,123 @@
# Q-Score Service Scaffold (UV + FastAPI) - Reference
Goal: mirror `growqr/job-service/` structure, but use `uv` + `pyproject.toml` + `uv.lock`.
## 1) Target Folder Structure
Proposed repo path: `growqr/qscore-service/`
```
qscore-service/
.env.example
.gitignore
README.md
docker-compose.yml
Dockerfile
pyproject.toml
uv.lock
app/
__init__.py
main.py
config.py
database.py
api/
__init__.py
v1/
__init__.py
router.py
signals.py
qscore.py
registry.py
formulas.py
auth/
__init__.py
middleware.py
schemas/
__init__.py
signals.py
qscore.py
formulas.py
services/
__init__.py
engine_service.py
scoring/
__init__.py
engine/
__init__.py
loader.py
evaluator.py
breakdown.py
formula/
v1/
formula.json
alembic/
env.py
versions/
scripts/
run_worker.py
```
Notes:
- This keeps the same mental model as `growqr/job-service/app/...`.
- We include Alembic so schema changes are migration-driven (job-service currently uses create_all).
## 2) UV Commands (Day 1)
Create project:
```bash
uv init .
uv python pin 3.12
uv venv
```
Add runtime deps:
```bash
uv add fastapi "uvicorn[standard]" pydantic pydantic-settings sqlalchemy asyncpg
uv add redis
```
Add dev deps:
```bash
uv add --dev ruff black pytest pytest-asyncio
```
Lock + sync:
```bash
uv lock
uv sync --frozen
```
Run:
```bash
uv run uvicorn app.main:app --host 0.0.0.0 --port 8000 --reload
```
## 3) Dockerfile Pattern (UV)
Use the recommended uv-based Docker pattern:
- copy `pyproject.toml` + `uv.lock`
- `uv sync --frozen --no-dev`
- copy `app/`
## 4) Migration Setup (Alembic)
We use Alembic for Postgres schema:
- `alembic init alembic`
- configure `DATABASE_URL` in `app/config.py`
- import SQLAlchemy Base metadata in `alembic/env.py`
## 5) How This Matches job-service
`growqr/job-service/app/` has:
- `main.py`, `config.py`, `database.py`
- `api/v1/router.py` to include routes
- `schemas/` + `services/`
Q-score service follows the same layout so engineers can jump between services without relearning structure.

View File

@@ -0,0 +1,250 @@
# Requirements: Curator Streak Chat Flow — Service Handoff & Preview UX
**Date:** 2026-06-15
**Status:** Draft — pending stakeholder review
**Repos:** `growqr-backend`, `growqr-dashboard`
**Branch:** `staging-rosh` (VPS staging)
**Priority:** P0 — main blocker for staging user testing
---
## 1. Goal
When a user clicks a daily/weekly streak or progress suggestion in the GrowQR dashboard, the system must guide them through a focused, coherent conversation that produces a **service preview CTA** — not a blank setup screen — so they can immediately start the intended service (interview, roleplay, resume, etc.) with sensible defaults derived from their onboarding profile and goals.
**What good looks like:** a user who clicks "practice behavioral interview" gets asked at most one clarifying question, then sees a clear card with a button that says "Open interview preview" and lands directly on a preview screen with the role, round type, and difficulty already set.
---
## 2. Scope — What This Covers
| In Scope | Out of Scope |
|----------|-------------|
| Streak/weekly progress component chat modal | TalkToMe chat route/component |
| Curator backend prompt behavior | New AI model selection |
| Interview preview handoff | Resume parser internals |
| Roleplay preview handoff | Q Score calculation engine |
| Service CTA card rendering | Social branding / courses |
| Prompt externalization | Billing/subscription flows |
| 3-suggestion daily task model | Admin dashboards |
| 30/60-day growth plan coherence | Full mission actor rewrite |
---
## 3. Stakeholder Experience — The Exact Flow
### 3.1 User Lands on Dashboard
The user sees:
- **Streak progress** (e.g., "5-day streak 🔥")
- **Weekly progress** with 3 suggestions
- Each suggestion has a title, subtitle, and an actionable CTA
The suggestions are derived from the user's onboarding answers (ICP, goals, blockers) and current Q Score / readiness state.
### 3.2 User Clicks a Suggestion
Example: **"Practice behavioral interview — Product Manager"**
A chat modal opens. The assistant header shows:
- Avatar + "Daily Mission" label
- Subtask title: "Practice behavioral interview"
- Service name: "Interview Coach"
### 3.3 First Turn
The curator should **not** ask a generic "What do you want to do?" question.
It should say something like:
> "Ill set up a 5-minute behavioral interview preview for you. What role should I focus on — or is Product Manager still your target?"
If the onboarding already captured the role, it should **skip the question entirely** and proceed directly to the preview card.
### 3.4 User Answers (or Skips)
- User types: "Product Manager" (or just hits Enter if already known)
- Assistant: "Got it. Preparing your preview now."
### 3.5 Preview CTA Card Appears
A card appears in the chat with:
- **Eyebrow:** INTERVIEW PREVIEW
- **Title:** "Your mock interview is ready"
- **Details:** Role · Round · Difficulty · Duration
- **Button:** "Open interview preview" (or "Open roleplay preview")
- **Secondary link:** "Change settings" (opens setup with params pre-filled)
### 3.6 User Clicks the CTA
The user is routed to:
```
/agents/interview/preview?role=Product+Manager&type=behavioral&difficulty=medium&duration=5&source=curator-v1&curatorTaskId=...
```
The preview page loads with the session already configured. The user can:
- Start the interview immediately
- Request question changes
- Go back to chat
### 3.7 Roleplay Equivalent
Same flow, but for roleplay:
> "Ill set up a salary negotiation practice. What scenario should we rehearse?"
Then CTA card → `/agents/roleplay/preview?scenario=...` or equivalent builder route with pre-filled params.
---
## 4. Acceptance Criteria — What "Finish" Looks Like
### 4.1 Backend Acceptance Criteria
| # | Criteria | How to Verify |
|---|----------|---------------|
| B1 | Curator prompt is externalized to a markdown/txt file | `cat prompts/curator/daily-retention-system.md` returns the prompt |
| B2 | Interview handoff returns preview route, not setup | `/v1/curator/chat` response includes `handoff.actionRoute` containing `/agents/interview/preview` |
| B3 | Roleplay handoff returns preview route, not setup | Same as B2, but for roleplay |
| B4 | Status is `handoff_ready` when service context is sufficient | `statusUpdate.status === "handoff_ready"` after one answer for known role |
| B5 | No infinite questioning — max 1 clarifying question per service task | Log review: assistant never asks same question twice |
| B6 | Default params are sensible: `type=behavioral`, `difficulty=medium`, `duration=5` | Preview loads without user needing to configure |
| B7 | Route includes onboarding-derived role when available | `role` param is pre-filled from user profile |
| B8 | Curator does not leak internal routes in chat text | No `/agents/...` URLs in `reply` field |
| B9 | Service handoff works for Resume (workspace), Q Score (review), Pathways (report) | Each returns correct route with pre-filled context |
| B10 | Build passes on VPS | `npm run typecheck` and `npm run build` succeed on staging-rosh |
### 4.2 Frontend Acceptance Criteria
| # | Criteria | How to Verify |
|---|----------|---------------|
| F1 | Streak chat shows service preview CTA card reliably | Click interview suggestion → card appears within 2 turns |
| F2 | CTA card is visually distinct and action-oriented | Card has eyebrow, title, details grid, and primary button |
| F3 | CTA persists after subtask is marked complete | Even in "completed" footer state, the card remains visible |
| F4 | Button copy is service-specific | Interview: "Open interview preview"; Roleplay: "Open roleplay preview"; Resume: "Open resume workspace" |
| F5 | Clicking CTA navigates to correct preview route | Browser URL matches `/agents/interview/preview?...` or `/agents/roleplay/preview?...` |
| F6 | Preview page loads with pre-filled params | Interview preview shows role, type, difficulty without user re-entering |
| F7 | No regression to TalkToMe, home feed, or other dashboard pages | Smoke test: dashboard, talk-to-me, missions, settings all load |
| F8 | Build passes on VPS | `npm run build` succeeds on staging-rosh |
| F9 | Mobile: chat modal and CTA card are usable | Test on mobile viewport: card readable, button tappable |
| F10 | Loading state is clear and non-blocking | "Preparing your preview..." shown instead of generic spinner |
### 4.3 Product Coherence Criteria
| # | Criteria | How to Verify |
|---|----------|---------------|
| P1 | Every task connects back to user's stated goal | Chat copy references user's target role or goal from onboarding |
| P2 | 30/60-day plan framing is visible | Suggestion labels include week/day context (e.g., "Week 2 — Day 3") |
| P3 | Tasks follow the 3-suggestion model: Measurement + Proof + Practice | Daily suggestions show one of each category |
| P4 | Streak is meaningful — not just a counter | Completing a task shows progress toward a goal, not just +1 day |
| P5 | User can see why this task matters | Assistant explains: "This builds your interview readiness signal, which improves your Q Score." |
---
## 5. Non-Functional Requirements
| Requirement | Target |
|-------------|--------|
| Curator chat response time | < 3s end-to-end (backend + frontend) |
| Preview page load time | < 2s after CTA click |
| Build time on VPS | < 5 minutes per repo |
| Downtime during deploy | Zero rolling restart via Docker Compose |
| Prompt hot-reload | Possible without code redeploy (external file) |
| Browser compatibility | Chrome, Safari, Firefox latest 2 versions |
---
## 6. Edge Cases & Error Handling
| Scenario | Expected Behavior |
|----------|-----------------|
| User gives vague answer | Assistant asks ONE follow-up, then shows preview card with best guess |
| User has no onboarding role | Assistant asks "What role are you targeting?" answer generates preview |
| Service is temporarily down | Assistant shows "Service is warming up try again in a moment" instead of broken link |
| User clicks CTA but preview fails | Preview page shows friendly error with "Go back to chat" button |
| User refreshes dashboard mid-chat | Chat state is lost acceptable for MVP; later: conversation persistence |
| User is on mobile | Modal is full-screen, CTA card is thumb-friendly, no horizontal scroll |
| User has multiple active missions | Curator picks the most relevant mission context for the task |
| User is a new Day 1 user | Suggestions are simpler: Q Score baseline, Resume upload, Warm-up interview |
---
## 7. Success Metrics
Once deployed to staging, we will measure:
| Metric | Baseline | Target |
|--------|----------|--------|
| Interview preview CTA visibility rate | 0% (broken) | 100% when interview task is active |
| Roleplay preview CTA visibility rate | 0% (broken) | 100% when roleplay task is active |
| User reaches preview page after CTA click | N/A | > 90% of clicks |
| Avg chat turns to preview | N/A | ≤ 2 turns |
| Chat abandonment rate | N/A | < 20% |
| Build pass rate | N/A | 100% |
| Staging smoke test pass | N/A | 100% of test cases |
---
## 8. Dependencies
| Dependency | Status | Owner |
|------------|--------|-------|
| Interview service preview page | Exists | Interview service team |
| Roleplay service preview page | Needs verification | Roleplay service team |
| Backend curator routes | Exists | Backend team |
| Dashboard streak component | Exists | Dashboard team |
| Onboarding ICP mapping | Exists | Product (docs) |
| 30-day plan examples | Exists | Product (docs) |
| VPS staging environment | Running | DevOps |
---
## 9. Open Questions
| # | Question | Impact |
|---|----------|--------|
| Q1 | Does roleplay have a true `/preview` route, or should we use `/setup` with pre-filled params? | Determines route generation in backend |
| Q2 | Should resume handoff go to `/agents/resume` list or directly to editor? | UX flow |
| Q3 | Should Q Score handoff go to `/analytics` or `/agents/qscore`? | Route decision |
| Q4 | Do we want the assistant to stream tokens, or is JSON response acceptable for MVP? | Scope / time |
| Q5 | Should the curator chat be its own separate route from TalkToMe, or share the conversation actor? | Architecture |
---
## 10. Definition of Done
This requirement is **finished** when:
1. All backend acceptance criteria (B1B10) pass on staging
2. All frontend acceptance criteria (F1F10) pass on staging
3. All product coherence criteria (P1P5) are verified by stakeholder
4. Staging VPS is stable no crashes, no 500s, no broken routes
5. User can click a streak suggestion chat preview CTA preview page start service, in under 5 interactions
6. Prompt file is externalized and editable without code redeploy
7. Changes are committed to `staging-rosh` on both repos
8. Staging smoke test passes for all 6 test cases (Section 4)
---
## 11. Related Documents
- `docs/curator-icp-task-subtask-playbook.md` ICP taxonomy and task libraries
- `docs/curator-icp-comprehensive-playbook.md` Full service definitions and 30-day plans
- `docs/curator-30day-examples-by-icp.md` Copy-pasteable 30-day plans, chat flows, prompt templates
- `docs/staging-vps-service-deployment-runbook.md` VPS deployment procedures
---
## 12. Sign-off
| Role | Name | Status |
|------|------|--------|
| Product Owner | Rosh | Pending review |
| Backend Lead | | Pending assignment |
| Frontend Lead | | Pending assignment |
| QA / Staging | | Pending test execution |
---
*End of requirements document*

463
runbook.md Normal file
View File

@@ -0,0 +1,463 @@
# GrowQR Demo Runbook
Use this when restarting the full local demo after everything has been stopped. It should bring back the workflows dashboard, growqr-app frontend session launchers, backend, Rivet workflow actor runner, interview-service, roleplay-service, QScore service, resume-builder, matchmaking, and the per-user Gitea/OpenCode stack.
## What Must Be Running
- Docker Desktop
- `qscore-service`: Postgres, Redis, API, worker
- `interview-service`: API, Postgres, MinIO, bucket setup
- `roleplay-service`: API, Postgres, MinIO, bucket setup
- `resume-builder`: Docker container with Postgres (port 5433), API (port 8002)
- `matchmaking`: API on host port 8006
- `growqr-backend`: backend Postgres plus local Node backend
- `workflows--dashboard`: Next.js frontend
- `growqr-app/frontend`: Next.js frontend for the new interview/roleplay session UI
- Per-user OpenCode containers, created by backend provisioning (Gitea is central/shared)
The known demo ports are:
- Workflows dashboard: `http://localhost:3000`
- GrowQR app frontend session launchers: `http://localhost:3002`
- Backend: `http://localhost:4000`
- Backend Rivet proxy: `http://localhost:4000/api/rivet`
- Interview service: `http://localhost:8007`
- Roleplay service: `http://localhost:8008`
- QScore service: `http://localhost:8000`
- Resume builder: `http://localhost:8002`
- Matchmaking service: `http://localhost:8006`
- Resume builder DB: `localhost:5433`
- QScore Redis: `localhost:6379`
- Central Gitea: `http://localhost:3001` (shared org-wide, changes.md §2A)
- Backend Postgres: `localhost:5432`
- Per-user OpenCode containers: dynamically allocated from `20000-29999`
## Required Env Files
Before starting, verify these files exist and contain the local demo values:
- `growqr-backend/.env`
- `growqr-backend/.env.local`
- `workflows--dashboard/.env.local`
- `growqr-app/frontend/.env.local`
- `interview-service/.env`
- `roleplay-service/.env`
- `growqr-app/resume-builder/.env.local` (created by setup script)
Do not print secrets into chat or commit them. The important non-secret shape is:
- Backend service URLs should point to `127.0.0.1`:
- `INTERVIEW_SERVICE_URL=http://127.0.0.1:8007`
- `ROLEPLAY_SERVICE_URL=http://127.0.0.1:8008`
- `QSCORE_SERVICE_URL=http://127.0.0.1:8000`
- `RESUME_SERVICE_URL=http://127.0.0.1:8002`
- `MATCHMAKING_SERVICE_URL=http://127.0.0.1:8006`
- `GROWQR_APP_FRONTEND_URL=http://localhost:3002`
- Backend per-user containers should use:
- `OPENCODE_IMAGE=ghcr.io/anomalyco/opencode:latest`
- `USER_CONTAINER_HOST=127.0.0.1`
- `USER_DATA_ROOT=./.data/users`
- Frontend should use:
- `NEXT_PUBLIC_RIVET_ENDPOINT=http://127.0.0.1:4000/api/rivet`
- `NEXT_PUBLIC_GROWQR_BACKEND_URL=http://127.0.0.1:4000` (NOT `GROWQR_BACKEND_URL` — must have NEXT_PUBLIC_ prefix for client-side)
- `OPENCODE_API_KEY=<from backend .env>` (must match backend)
- `LLM_BASE_URL=https://opencode.ai/zen/v1`
- `LLM_MODEL=kimi-k2.6`
- Resume builder should use:
- `DATABASE_URL=postgresql+asyncpg://postgres:postgres@host.docker.internal:5433/growqr_resume` (host.docker.internal when running in Docker, localhost when running locally)
- `API_PORT=8002`
- `OPENCODE_API_KEY=<from backend .env>`**CRITICAL: must be the EXACT same key as backend.** Both services share the same OpenCode account.
- `OPENCODE_BASE_URL=https://opencode.ai/zen/v1`
- `AI_MODEL=kimi-k2.6`
- `CLERK_JWKS_URL=https://noted-elephant-23.accounts.dev/.well-known/jwks.json`
- `CLERK_ISSUER=https://noted-elephant-23.accounts.dev`
- `CORS_ORIGINS="http://localhost:3000,http://localhost:3001,http://127.0.0.1:3000"`
- `A2A_ALLOWED_KEYS=dev-a2a-key`
- `REDIS_URL=redis://host.docker.internal:6379/0`
- `DEBUG=true`
- `SERVICE_TOKEN` and `A2A_ALLOWED_KEY` must match across backend and services.
- Clerk keys must match between frontend and backend.
- Gemini and OpenCode keys must be present for the audio/session and LLM paths.
### OpenCode API Key Sync (IMPORTANT)
The backend and resume-builder share the same OpenCode API key. When copying values, always use `growqr-backend/.env` as the **source of truth**. The resume-builder's `.env.local` was previously out of sync (25-char dummy key vs 67-char real key), causing silent LLM failures.
To verify keys are synced:
```bash
diff <(grep OPENCODE_API_KEY growqr-backend/.env | head -1) <(grep OPENCODE_API_KEY growqr-app/resume-builder/.env.local | head -1)
# Should show no differences
```
Note: interview-service and roleplay-service use Gemini (not OpenCode) — they don't need an OpenCode key.
## Start Order
Run all commands from `/Users/divyansh/Desktop/growQR` unless a command changes directory.
### 0. Start Central Gitea first (NEW per changes.md §2A)
The central Gitea is now a shared compose service in the backend's docker-compose. **Note:** Gitea health check uses port 3000 internally (container), mapped to 3001 on host. Port mapping is `3001:3000`.
```bash
docker compose -f growqr-backend/docker-compose.yml up -d gitea
```
Wait until Gitea is healthy (~30 seconds on first startup):
```bash
curl http://127.0.0.1:3001/api/v1/version
# Expected: {"version":"1.22.6"}
```
Per-user Gitea containers are NO LONGER spawned dynamically. All users share the central Gitea instance with one repo per user under the `growqr` org.
### 1. Start QScore first
QScore owns the Redis instance exposed on `localhost:6379`. The interview service currently uses that host Redis for workflow task dispatch, so QScore should come up first.
```bash
docker compose -f qscore-service/docker-compose.yml up -d --build
```
Wait until all QScore containers are healthy/running:
```bash
docker compose -f qscore-service/docker-compose.yml ps
curl http://127.0.0.1:8000/health
# Expected: {"status":"ok"}
```
### 2. Start Interview Service
```bash
docker compose -f interview-service/docker-compose.yml up -d --build
```
Verify:
```bash
curl http://127.0.0.1:8007/health
# Expected: {"status":"ok","service":"interview-service","a2a":true,"agent":true}
```
### 3. Start Roleplay Service
```bash
docker compose -f roleplay-service/docker-compose.yml up -d --build
```
Verify:
```bash
curl http://127.0.0.1:8008/health
# Expected: {"status":"ok","service":"roleplay-service","a2a":true,"agent":true}
```
### 4. Start Resume Builder (NEW)
The resume builder runs as a Docker container built from `growqr-app/resume-builder/Dockerfile`. It uses its own Postgres database on port 5433.
```bash
# Start resume-builder Postgres
docker compose -f growqr-app/resume-builder/docker-compose.yml up -d postgres
# Build resume-builder image (first time only)
docker build -t growqr-resume-builder growqr-app/resume-builder
# Run migrations
cd growqr-app/resume-builder
uv run --env-file .env.local alembic upgrade head
# Start the service with synced OpenCode key from backend
cd /Users/divyansh/Desktop/growQR
OPENCODE_KEY=$(grep OPENCODE_API_KEY growqr-backend/.env | head -1 | cut -d= -f2)
docker rm -f growqr-resume-builder 2>/dev/null
docker run -d --name growqr-resume-builder \
-p 8002:8002 \
-e DATABASE_URL=postgresql+asyncpg://postgres:postgres@host.docker.internal:5433/growqr_resume \
-e OPENCODE_API_KEY="${OPENCODE_KEY}" \
-e OPENCODE_BASE_URL=https://opencode.ai/zen/v1 \
-e AI_MODEL=kimi-k2.6 \
-e CLERK_JWKS_URL=https://noted-elephant-23.accounts.dev/.well-known/jwks.json \
-e CLERK_ISSUER=https://noted-elephant-23.accounts.dev \
-e CORS_ORIGINS="http://localhost:3000,http://localhost:3001,http://127.0.0.1:3000" \
-e A2A_ALLOWED_KEYS=dev-a2a-key \
-e REDIS_URL=redis://host.docker.internal:6379/0 \
-e DEBUG=true \
growqr-resume-builder uvicorn app.main:app --host 0.0.0.0 --port 8002
# Verify
curl http://127.0.0.1:8002/health
# Expected: {"status":"healthy","service":"resume-builder","mcp":true,"agent":true,"a2a":true}
```
### 5. Start Backend Postgres
For the demo path that avoids Rivet `no_capacity`, run the backend locally with its embedded Rivet runner and start only the backend Postgres from compose:
```bash
docker compose -f growqr-backend/docker-compose.yml up -d postgres
```
**Important:** If the backend was previously running with older schema, you may need to add missing columns:
```bash
docker exec growqr-postgres psql -U growqr -d growqr -c "
ALTER TABLE user_stacks ADD COLUMN IF NOT EXISTS gitea_repo_name TEXT;
ALTER TABLE user_stacks ADD COLUMN IF NOT EXISTS gitea_repo_owner TEXT;
ALTER TABLE user_stacks ADD COLUMN IF NOT EXISTS image_version TEXT;
ALTER TABLE user_stacks ADD COLUMN IF NOT EXISTS migration_version TEXT;
ALTER TABLE user_stacks ADD COLUMN IF NOT EXISTS prompt_version TEXT;
"
```
Then migrate:
```bash
cd /Users/divyansh/Desktop/growQR/growqr-backend
npm run db:migrate
```
Start the backend:
```bash
cd /Users/divyansh/Desktop/growQR/growqr-backend
RIVET_RUN_ENGINE=1 npm run dev
```
Keep this terminal open. Verify in a separate terminal:
```bash
curl http://127.0.0.1:4000/healthz
# Expected: {"ok":true}
```
The backend will auto-provision OpenCode containers for existing users on boot (reconcileOnBoot).
### 6. Start Matchmaking
The matchmaking service powers the Scout/job-search handoff. It runs on port 8000 internally and port 8006 on the host.
```bash
docker compose -f matchmaking/docker-compose.yml up -d --build
curl http://127.0.0.1:8006/api/v1/health
# Expected: {"status":"healthy", ...}
```
### 7. Start Frontends
Start the dashboard on port 3000:
```bash
cd /Users/divyansh/Desktop/growQR/workflows--dashboard
npm run build
npm run start
```
Start the growqr-app frontend on port 3002. This app now owns the product UI for interview and roleplay sessions launched from workflow chat.
```bash
cd /Users/divyansh/Desktop/growQR/growqr-app/frontend
npm install --legacy-peer-deps
npm run dev -- -p 3002
```
Keep both terminals open. Open:
```text
http://localhost:3000/v2/workflows
```
## Provision OpenCode Containers
OpenCode containers are per-user and spawned dynamically by the backend Docker manager. Gitea is NO LONGER per-user — it's a central shared service (changes.md §2A).
After provisioning, `docker ps` should show containers with names like:
```text
growqr-opencode-user_<userId>
```
If they are missing, sign into the dashboard and allow the user stack bootstrap to run. The local data is under:
```text
growqr-backend/.data/users
```
That folder is intentionally gitignored and should stay local.
## Demo Path — Interview-to-Offer Accelerator
Use this path for the Interview-to-Offer workflow demo:
1. Open `http://localhost:3000/v2/workflows`.
2. Type in the chat: `I have an interview at Google for SWE`
3. The AI responds with a conversational message and the **WorkflowDiscovery card** (red, 4 agents, 4 steps) appears below.
4. Click **"Start this workflow"** on the card.
5. The workflow progresses step-by-step:
- **Step 1**: AI asks for job description → you respond with details
- **Step 2**: AI asks for resume → you respond
- **Step 3**: Resume Agent analyzes and tailors (shows "DONE")
- **Step 4**: Sara interview session ready → shows **"Open" button**
- **Step 5**: Emily roleplay session ready → shows **"Open" button**
- **Step 6**: Quinn computes Q-Score → shows results
6. Click **Open** on Sara's card → new tab opens `http://localhost:3002/service-sessions/interview?session_id=<uuid>...`
7. On the new GrowQR interview launcher, click **Start interview** and allow microphone/camera access.
8. Click **Open** on Emily's card → new tab opens `http://localhost:3002/service-sessions/roleplay?session_id=<uuid>...`
9. On the new GrowQR roleplay launcher, click **Start roleplay** and allow microphone/camera access.
10. Completed steps are marked with **green checkmarks** in the chat.
### Alternative Workflow Trigger Queries
| Workflow | Trigger Query |
|---|---|
| Interview-to-Offer | `I have an interview at Google for SWE` |
| Career Switch | `I want to switch from marketing to product management` |
| Resume Boost | `My resume isn't getting any responses` |
| Job Search | `Find me backend engineering jobs` |
| Job Preparation | `Prepare me for a role at Stripe` |
Direct service demo pages are for low-level service debugging only. Product workflow links should use the new `growqr-app/frontend` launchers:
```text
http://localhost:3002/service-sessions/interview?session_id=<uuid>
http://localhost:3002/service-sessions/roleplay?session_id=<uuid>
```
## Health Checks
Use these after startup:
```bash
curl http://127.0.0.1:4000/healthz # Backend
curl http://127.0.0.1:8007/health # Interview
curl http://127.0.0.1:8008/health # Roleplay
curl http://127.0.0.1:8000/health # QScore
curl http://127.0.0.1:8002/health # Resume builder
curl http://127.0.0.1:8006/api/v1/health # Matchmaking
curl -I 'http://localhost:3002/service-sessions/interview?session_id=demo-interview'
curl -I 'http://localhost:3002/service-sessions/roleplay?session_id=demo-roleplay'
curl http://127.0.0.1:3001/api/v1/version # Gitea
docker ps # All containers
```
If the workflow actor fails with `no_capacity`, restart the backend with:
```bash
cd /Users/divyansh/Desktop/growQR/growqr-backend
RIVET_RUN_ENGINE=1 npm run dev
```
## Shutdown
Stop frontend and backend with `Ctrl+C` in their terminals.
**Also kill any lingering backend Node processes:**
```bash
pkill -f "tsx watch" 2>/dev/null
pkill -f "tsx.*src/index" 2>/dev/null
```
Stop compose services:
```bash
docker compose -f growqr-backend/docker-compose.yml down
docker compose -f interview-service/docker-compose.yml down
docker compose -f roleplay-service/docker-compose.yml down
docker compose -f qscore-service/docker-compose.yml down
docker compose -f matchmaking/docker-compose.yml down
docker compose -f growqr-app/resume-builder/docker-compose.yml down
docker rm -f growqr-resume-builder
```
Stop per-user OpenCode containers if still running:
```bash
docker ps --filter "name=growqr-opencode-user"
```
Then stop/remove the shown containers by name:
```bash
docker stop <growqr-opencode-container>
docker rm <growqr-opencode-container>
```
They can be recreated later by the backend provisioning flow. The local persistent data remains in `growqr-backend/.data/users`.
## Build Rule
Whenever code changes are made, run the relevant build before calling the demo ready:
```bash
cd /Users/divyansh/Desktop/growQR/growqr-backend && npm run build
cd /Users/divyansh/Desktop/growQR/workflows--dashboard && npm run build
cd /Users/divyansh/Desktop/growQR/growqr-app/frontend && npm run build
```
For Dockerized Python services, rebuild with their compose commands:
```bash
docker compose -f interview-service/docker-compose.yml up -d --build
docker compose -f roleplay-service/docker-compose.yml up -d --build
docker compose -f qscore-service/docker-compose.yml up -d --build
```
## Agent Architecture & Flow
The system has 5 real service-backed agents:
| Agent | Name | Service | Port | Provider | Creates |
|---|---|---|---|---|---|
| Resume Agent | Mira | resume-builder | 8002 | OpenCode (kimi-k2.6) | Resume analysis + tailoring |
| Interview Agent | Sara | interview-service + growqr-app frontend launcher | 8007 + 3002 | Gemini (audio) | Live interview sessions in new UI |
| Roleplay Agent | Emily | roleplay-service + growqr-app frontend launcher | 8008 + 3002 | Gemini (audio) | Roleplay scenario sessions in new UI |
| Q-Score Agent | Quinn | qscore-service | 8000 | Internal formula | Readiness scores |
| Job Search Agent | Scout | matchmaking | 8006 | Internal ranking engine | Ranked opportunity feed |
### Chat Flow (Conversational Step-by-Step)
1. User types message → Frontend sends to `POST http://127.0.0.1:4000/api/chat` (with Clerk auth)
2. Backend tries Rivet actor first, falls back to direct LLM with tools
3. LLM responds conversationally OR calls a tool (`start_interview_session`, `analyze_resume`, etc.)
4. If tool is called, backend executes it against the real microservice
5. Response includes `{ reply, sessions[], workflow }` — sessions contain real URLs
6. Frontend renders agent cards with photos, status badges, and **Open** buttons
### Trigger Queries (what to type)
| For this agent | Type this |
|---|---|
| Resume analysis | `analyze my resume for Google SWE` |
| Interview session | `launch a behavioral interview for Software Engineer at Google` |
| Roleplay session | `launch a roleplay for negotiating a Google offer` |
| Q-Score | `compute my Q-Score` |
| Full workflow | `I have an interview at Google for SWE` |
### Session URLs
When a session is created, the backend preserves the `session_id` from the service configure response and returns one of these product URLs:
- Interview: `http://localhost:3002/service-sessions/interview?session_id=<uuid>&role=<goal>&type=<type>`
- Roleplay: `http://localhost:3002/service-sessions/roleplay?session_id=<uuid>&goal=<goal>&type=<type>`
The old direct demo pages still exist for service debugging, but workflow chat should not link to them.
### Key Files
- System prompt: `growqr-backend/prompts/system.txt`
- Agent definitions: `growqr-backend/agents/*.md`
- Service probes: `growqr-backend/src/services/service-agents.ts`
- Chat route (with tool dispatch): `growqr-backend/src/routes/chat.ts`
- Frontend chat component: `workflows--dashboard/src/components/home-v2/GrowChat.tsx`
- New service launchers: `growqr-app/frontend/src/app/service-sessions/interview/page.tsx`, `growqr-app/frontend/src/app/service-sessions/roleplay/page.tsx`
- Product flow requirements: `.growqr_memory.md`
### Known Quirks
- **Roleplay configure is slow** (30-60s): The roleplay service calls an LLM to generate scenarios. Be patient.
- **Rivet `/actors` returns 400**: Cosmetic console warning from the Rivet frontend SDK. Does not affect chat — chat uses HTTP fallback.
- **Rivet proxy vs handler conflict**: When `RIVET_RUN_ENGINE=1`, the backend proxies `/api/rivet/*` to the engine at `localhost:6420` instead of using `registry.handler()`. This avoids the "Runtime already started as runner" error.
- **Multiple backend processes**: `tsx watch` sometimes spawns orphans. Always `pkill -f "tsx watch"` before restarting.

View File

@@ -0,0 +1,615 @@
# GrowQR Market-Aligned Sellable Workflows Catalog
This catalog is intentionally **not constrained by the primitives GrowQR has today**. It uses the current primitives inventory as an implementation reference, but the portfolio is organized around the broader market described by the GrowQR landing page: **one career identity, specialized AI agents, human experts, QX score, verified achievements, deep matching, and workflows for Students, Individuals, Coaches, Freelancers, Startups, Recruiters, Enterprises, and Institutes.**
The product surface is not “Resume Builder + Interview Tool + Matchmaking.” The product surface is:
> **Your career/opportunity co-pilot: an AI agent squad plus human experts that turns identity, skills, proof, and ambition into outcomes.**
---
## 1. Landing Page Positioning Signals
The workflow catalog should map to these public promises.
### 1.1 Core promise
- **One QR for everything you are** — a portable career/professional identity.
- **QX-Score** — 25 signals condensed into a meaningful readiness/trust score.
- **Personalized AI** — agents learn as the user grows.
- **Verified achievements** — proof that cannot be faked.
- **Deep matching** — matching across jobs, gigs, internships, teams, courses, mentors, and opportunities.
- **Human intelligence** — coaches, mentors, experts, interviewers, and advisors when AI is not enough.
### 1.2 Public agent squad
| Agent | Market role |
|---|---|
| Scout — Opportunity Finder | Finds jobs, internships, gigs, candidates, clients, and other opportunities |
| Mira — Resume Expert | Converts user history into strong applications/profiles |
| Vera — Interviewer | Simulates and scores real interviews |
| Kai — Roleplay Coach | Practices hard professional conversations |
| Nova — Brand Voice | Builds public visibility, positioning, and content |
| Sage — Skill Trainer | Diagnoses gaps and builds improvement plans |
| Lyra — Learning Curator | Curates courses and learning paths |
| Atlas — Pathway Guide | Maps career options, pivots, and next steps |
| Drape — Presence Coach | Coaches appearance, speech, room presence, and professional behavior |
### 1.3 Market segments from the landing page
| Segment | Landing-page ambition | Workflow implication |
|---|---|---|
| Students | Discover career fit, land first internship, learn relevant skills | B2C + institutional placement-readiness products |
| Individuals | Find a job that fits who they are | Job search, career fit, interview, resume, brand, negotiation |
| Coaches | Find clients who value and pay for their work | Expert marketplace, client pipeline, outcome proof |
| Freelancers | Find gigs that respect their skills and rates | Gig matching, pricing, portfolio, client acquisition |
| Startups | Build the right team from day one | Team design, candidate matching, early hiring workflows |
| Recruiters | Find the right candidate fast | Candidate intelligence, screening, matching, pipeline products |
| Enterprises | Keep best people happy | Retention, internal mobility, upskilling, manager intelligence |
| Institutes | Make every student placement-ready | Cohort readiness, placement ops, employer matching |
---
## 2. Coherence Filter
A workflow is top-level only if it satisfies most of these:
1. **Market-facing ambition:** It maps to a named user/segment ambition.
2. **Outcome promise:** It changes a real-world state: hired, matched, promoted, retained, paid, certified, placed, booked, or discovered.
3. **Economic buyer:** Someone has a clear reason to pay: user, parent, institution, employer, recruiter, startup, coach, or freelancer.
4. **Repeatability:** It can be rerun daily/weekly/monthly or across cohorts/pipelines.
5. **Data compounding:** It strengthens the QR identity, QX score, talent graph, or verified achievement layer.
6. **Human escalation:** It can route to a coach, mentor, interviewer, advisor, or expert when trust matters.
7. **Marketplace potential:** It can create supply/demand liquidity across users, experts, jobs, gigs, institutions, and employers.
### 2.1 What is not a top-level workflow
| Idea | Better treatment |
|---|---|
| Resume Builder | Capability inside application, career identity, and job workflows |
| Interview Tool | Capability inside job, internship, promotion, and recruiter workflows |
| Roleplay Tool | Capability inside negotiation, sales, leadership, interview, and presence workflows |
| QX Score | Measurement/trust layer across all workflows |
| Opportunity Feed | Reusable surface inside job, internship, freelance, startup, recruiter, and institute workflows |
| Marketplace Human Expert | Escalation/add-on layer across workflows |
| LinkedIn Growth | Variant of visibility/brand workflows |
| Courses | Capability inside skill, placement, retention, and transition workflows |
| QR Profile | Identity substrate; can have its own onboarding workflow, but its bigger value is network-wide |
---
## 3. Value Ranking Method
The workflows below are sorted from **least to most valuable** by broader market/TAM potential, not by current implementation readiness.
Ranking factors:
- **TAM / buyer pool size**
- **ACV / willingness to pay**
- **Urgency and budget ownership**
- **Recurring revenue potential**
- **Network effects and data moat**
- **Cross-segment leverage**
- **Outcome measurability**
- **Strategic fit with GrowQR landing-page promise**
---
## 4. Market-Aligned Workflow Portfolio — Least to Most Valuable
### 1. Presence & Room Readiness Coach
**Primary segment:** Individuals, students, founders, leaders, interview candidates
**Value level:** Low-to-medium, high emotional appeal
**Promise:** “Tell me how to show up, speak, dress, and carry myself for this room.”
**Why it exists:** The landing page introduces Drape, the Presence Coach. This is distinctive and emotionally resonant, but narrower than hiring, retention, or placement workflows.
**Example use cases:** Interview outfit/readiness, first day at work, investor meeting, sales meeting, presentation, networking event, conference.
**Outputs:** Presence plan, dress guidance, speaking cues, room-specific checklist, roleplay practice, confidence score.
**Business model:** Low-cost one-time pack, premium add-on before interviews/events, coach upsell.
**Memory/data created:** Presence preferences, event contexts, confidence deltas, accepted/rejected recommendations.
---
### 2. Career QR Identity Setup
**Primary segment:** Everyone
**Value level:** Low direct monetization, high strategic acquisition
**Promise:** “Create one trusted QR identity for everything I am professionally.”
**Why it exists:** This is the foundation of the public promise: “One QR for everything you are.” It should likely be free or freemium because its main value is identity adoption and data compounding.
**Outputs:** Public/private QR profile, professional summary, skills, goals, proof links, portfolio, share settings, baseline QX score.
**Business model:** Free acquisition, premium profile enhancements, verification/credential upgrades, recruiter/employer unlocks.
**Memory/data created:** Identity graph, sharing permissions, profile claims, verified artifacts, baseline score.
---
### 3. Skill Gap & Learning Sprint
**Primary segment:** Students, individuals, enterprises, institutes
**Value level:** Medium
**Promise:** “Show me the exact skills blocking my next move and the shortest path to close them.”
**Why it ranks here:** Huge market, but crowded and indirect unless tied to a concrete opportunity, placement, promotion, or retention goal.
**Outputs:** Skill diagnosis, QX gap map, curated courses, project plan, assessment checkpoints, proof artifacts.
**Business model:** Individual sprint, course affiliate revenue, institute/enterprise cohort plans, marketplace tutor/mentor upsell.
**Memory/data created:** Skill graph, course progress, assessment outcomes, verified learning artifacts.
---
### 4. Career Discovery & Pathway Fit
**Primary segment:** Students, early-career users, career changers
**Value level:** Medium
**Promise:** “Help me discover what career actually fits me.”
**Why it ranks here:** Broad appeal and excellent onboarding, but payment urgency varies. It is a strong top-of-funnel workflow that routes users into higher-value outcomes.
**Outputs:** Career identity statement, pathway map, close/adjacent/stretch options, QX baseline, gap map, recommended opportunities and learning paths.
**Business model:** Free diagnostic, premium report, parent/student package, institute package, coach debrief.
**Memory/data created:** Ambition graph, pathway selection, preference data, strengths/weaknesses, long-term career plan.
---
### 5. Resume, Profile & Application Conversion Kit
**Primary segment:** Individuals, students, freelancers, coaches
**Value level:** Medium-high
**Promise:** “Turn my experience into materials that convert.”
**Why it ranks here:** Clear buyer intent and easy to understand. It is still usually a conversion component inside bigger job, internship, freelance, or coaching-client workflows.
**Outputs:** Resume, cover letter, LinkedIn/profile rewrite, portfolio narrative, pitch bio, job/gig-specific variants.
**Business model:** One-time purchase, per-application variant, premium human review, bundled with job/internship/gig search.
**Memory/data created:** Reusable narrative, achievements, proof points, target-role language, conversion history.
---
### 6. Interview & Roleplay Gym
**Primary segment:** Job seekers, students, salespeople, managers, founders
**Value level:** High
**Promise:** “Practice the real conversation before it matters.”
**Why it ranks here:** Strong urgency when an interview, sales call, negotiation, conflict, pitch, or presentation is near. Also has subscription potential as a professional practice gym.
**Outputs:** Mock interviews, roleplay sessions, transcripts, rubric scores, improvement plan, confidence trend, expert escalation.
**Business model:** One-time bootcamp, daily/weekly practice subscription, human interviewer/coach marketplace add-on, enterprise training package.
**Memory/data created:** Communication signals, behavior trends, readiness scores, role-specific practice history.
---
### 7. Personal Brand & Visibility Engine
**Primary segment:** Individuals, coaches, freelancers, founders, executives
**Value level:** High
**Promise:** “Make the right market notice and trust me.”
**Why it ranks here:** Broad market and recurring potential. It is especially valuable for freelancers/coaches/founders where visibility directly affects revenue.
**Outputs:** Positioning, content pillars, profile rewrites, post drafts, portfolio proof, audience plan, brand score, engagement strategy.
**Business model:** Monthly subscription, ghostwriter/coach upsell, freelancer/coach revenue packages, enterprise advocacy variant.
**Memory/data created:** Brand voice, audience response, market positioning, proof library, content performance.
---
### 8. First Internship / First Job Launchpad
**Primary segment:** Students, parents, institutes
**Value level:** High
**Promise:** “Get me from student to placement-ready, then into my first real opportunity.”
**Why it ranks here:** Strong emotional buyer, large global market, and B2B2C potential through institutes. Higher value than generic career discovery because the outcome is concrete.
**Outputs:** Student QR, readiness score, internship-ready resume, skill plan, opportunity shortlist, mock interview prep, weekly application plan, placement dashboard.
**Business model:** Student/parent package, institute cohort license, placement success fee, employer-sponsored talent pool.
**Memory/data created:** Student readiness graph, placement status, verified projects, cohort benchmarks, employer feedback.
---
### 9. Job Fit & Apply Autopilot
**Primary segment:** Individuals, active job seekers, passive switchers
**Value level:** Very high
**Promise:** “Find roles that actually fit me and help me apply well.”
**Why it ranks here:** Direct employment outcome, high urgency, recurring usage, and strong fit with Scout + Mira + Vera + Nova.
**Outputs:** Matched roles, fit explanations, tailored materials, outreach messages, tracker, interview prep, follow-up reminders.
**Business model:** Premium subscription, per-application sprint, success premium, expert resume/interview upsell.
**Memory/data created:** Job preferences, applied/rejected/advanced outcomes, fit signal feedback, employer response data.
---
### 10. Freelancer / Coach Revenue Engine
**Primary segment:** Freelancers, coaches, mentors, advisors, experts
**Value level:** Very high
**Promise:** “Find clients who value my expertise and help me sell at the right price.”
**Why it ranks here:** The landing page explicitly targets coaches and freelancers, not just job seekers. This opens a creator/service-provider TAM and seeds the human expert marketplace.
**Outputs:** Offer packaging, pricing guidance, QR service profile, credibility proof, lead list, outreach drafts, client call roleplay, booking funnel.
**Business model:** Monthly business-growth subscription, marketplace take rate, lead-gen fee, premium positioning package.
**Memory/data created:** Expert supply graph, service outcomes, conversion rates, pricing signals, verified client results.
---
### 11. Startup Team Builder
**Primary segment:** Startups, founders, early teams
**Value level:** Very high
**Promise:** “Help me design and hire the right early team.”
**Why it ranks here:** Higher ACV than individual workflows and direct hiring pain. It can connect candidate QR profiles, QX scores, interviews, roleplays, and advisor support.
**Outputs:** Team gap map, role specs, candidate shortlist, fit explanations, interview kits, founder-candidate roleplays, offer/closing guidance.
**Business model:** Startup subscription, per-role fee, success fee, advisor add-on.
**Memory/data created:** Startup team graph, role requirements, candidate fit outcomes, hiring signal data.
---
### 12. Recruiter Candidate Intelligence Workflow
**Primary segment:** Recruiters, staffing firms, hiring teams
**Value level:** Very high
**Promise:** “Find the right candidate faster, with more signal and less noise.”
**Why it ranks here:** Recruiters already have budget, urgency, and repeated demand. GrowQRs differentiation is verified identity, QX score, deep matching, and practice/performance signals.
**Outputs:** Ranked candidate lists, fit explanations, verified profile summaries, outreach drafts, screening packs, interview signals, pipeline analytics.
**Business model:** Recruiter seats, usage-based search credits, candidate unlocks, pipeline subscription, placement fee.
**Memory/data created:** Demand-side matching signals, recruiter feedback, candidate market value, hiring outcomes.
---
### 13. Institute Placement-Readiness OS
**Primary segment:** Universities, colleges, bootcamps, training institutes
**Value level:** Very high / enterprise-scale
**Promise:** “Make every student placement-ready and prove progress to employers.”
**Why it ranks here:** Large cohorts, institutional budgets, measurable outcomes, and strong alignment with students + first internship/job + verified achievements.
**Outputs:** Cohort dashboard, student QX baselines, readiness tracks, resume/interview completion, employer-ready QR profiles, placement pipeline, at-risk student alerts.
**Business model:** Annual SaaS per institution, per-student fee, placement success fee, employer sponsorship, premium coaching packages.
**Memory/data created:** Cohort benchmark graph, placement readiness data, verified achievement records, employer feedback loops.
---
### 14. Enterprise Retention & Internal Mobility OS
**Primary segment:** Enterprises, HR, talent development, people leaders
**Value level:** Highest ACV
**Promise:** “Keep our best people happy by matching them to growth, mobility, learning, and managers before they leave.”
**Why it ranks here:** Enterprise retention has large budgets and urgent ROI. Losing high performers is expensive. This expands GrowQR from career acquisition into workforce intelligence.
**Outputs:** Employee growth QR, internal mobility matches, skill gap plans, manager coaching scripts, flight-risk signals, learning recommendations, internal gig marketplace.
**Business model:** Enterprise SaaS, per-employee pricing, talent marketplace module, coaching marketplace take rate, analytics add-on.
**Memory/data created:** Workforce skill graph, internal opportunity graph, retention signals, manager/team health, growth-path outcomes.
---
### 15. Verified Talent & Opportunity Network
**Primary segment:** All segments
**Value level:** Highest strategic TAM / network moat
**Promise:** “Create a trusted network where people, proof, opportunities, experts, employers, and institutions match through verified identity and outcomes.”
**Why it ranks highest:** This is bigger than a workflow. It is the market network implied by the landing page: QR identity + QX score + verified achievements + AI agents + human experts + deep matching. Every workflow feeds it; every participant makes it more valuable.
**Network participants:** Students, workers, freelancers, coaches, mentors, recruiters, employers, startups, enterprises, institutes, course providers.
**Outputs:** Verified profiles, achievement credentials, opportunity graph, expert marketplace, matching APIs, trust scores, outcome records.
**Business model:** Multi-sided marketplace take rate, enterprise/institute SaaS, recruiter access, verification fees, premium identity, API/data products, success fees.
**Memory/data created:** Durable talent graph, proof graph, opportunity graph, outcome graph, reputation graph.
---
## 5. Portfolio Organization by Market Segment
### Students
- Career Discovery & Pathway Fit
- First Internship / First Job Launchpad
- Skill Gap & Learning Sprint
- Interview & Roleplay Gym
- Career QR Identity Setup
- Institute Placement-Readiness OS
### Individuals
- Job Fit & Apply Autopilot
- Resume, Profile & Application Conversion Kit
- Interview & Roleplay Gym
- Personal Brand & Visibility Engine
- Salary/negotiation and presence variants
- Career Discovery & Pathway Fit
### Coaches / Mentors / Advisors
- Freelancer / Coach Revenue Engine
- Personal Brand & Visibility Engine
- Career QR Identity Setup
- Verified Talent & Opportunity Network
- Human expert marketplace integrations
### Freelancers
- Freelancer / Coach Revenue Engine
- Personal Brand & Visibility Engine
- Interview & Roleplay Gym for sales/client calls
- Resume/Profile Conversion Kit adapted to portfolio/pitch
- Opportunity matching for gigs
### Startups
- Startup Team Builder
- Recruiter Candidate Intelligence Workflow
- Founder brand/presence variants
- Verified Talent & Opportunity Network
### Recruiters
- Recruiter Candidate Intelligence Workflow
- Verified Talent & Opportunity Network
- Interview/screening automation
- Candidate outreach and pipeline workflows
### Enterprises
- Enterprise Retention & Internal Mobility OS
- Skill Gap & Learning Sprint at workforce scale
- Interview & Roleplay Gym for management/sales/customer roles
- Personal Brand/employee advocacy variants
### Institutes
- Institute Placement-Readiness OS
- First Internship / First Job Launchpad
- Skill Gap & Learning Sprint
- Recruiter/employer matching portal
- Verified achievement/credential layer
---
## 6. Practical Launch Sequencing
### Phase 1 — Prove individual value and identity adoption
1. Career QR Identity Setup
2. Career Discovery & Pathway Fit
3. Resume, Profile & Application Conversion Kit
4. Job Fit & Apply Autopilot
5. Interview & Roleplay Gym
### Phase 2 — Build recurring usage and marketplace supply
6. Personal Brand & Visibility Engine
7. Skill Gap & Learning Sprint
8. Freelancer / Coach Revenue Engine
9. Human expert escalation across workflows
### Phase 3 — Expand into B2B/B2B2C
10. First Internship / First Job Launchpad
11. Institute Placement-Readiness OS
12. Startup Team Builder
13. Recruiter Candidate Intelligence Workflow
### Phase 4 — Build the strategic platform moat
14. Enterprise Retention & Internal Mobility OS
15. Verified Talent & Opportunity Network
---
## 7. Workflow Creation Template for Broader TAM
Use this when creating new workflows. It deliberately starts from market and TAM, not from current implementation.
```md
# Workflow: {Name}
## 1. Segment and Buyer
- User segment:
- Economic buyer:
- Budget owner:
- Buyer type: B2C / B2B / B2B2C / marketplace / platform
- Landing-page ambition this maps to:
## 2. User Promise
One sentence in the user's language:
“Help me {achieve concrete outcome}.”
## 3. Market/TAM Hypothesis
- How many people/organizations have this problem?
- How often does the problem occur?
- What do they already spend money on instead?
- What is the current alternative?
- Why can GrowQR be 10x better?
## 4. Urgency and Trigger Moment
- Trigger event:
- Deadline or pain intensity:
- Why now?
- What happens if the user does nothing?
## 5. Willingness to Pay
- ROI logic:
- Emotional value:
- Suggested price model:
- Expansion/upsell path:
## 6. Outcome Definition
- Primary outcome:
- Secondary outcomes:
- What would count as success in 7 days?
- What would count as success in 30/90 days?
## 7. Workflow Scope
- Start state:
- End state:
- In scope:
- Out of scope:
- Human escalation moments:
## 8. Agent Squad
- Lead agent:
- Supporting agents:
- Human expert type:
- New capability needed if not currently available:
## 9. Step Sequence
1. Capture ambition and context.
2. Build or update QR identity.
3. Establish baseline QX/readiness/trust score.
4. Diagnose gaps or opportunities.
5. Generate plan/options.
6. Ask for approval at first major decision.
7. Execute or prepare artifacts.
8. Match to opportunities/people/resources.
9. Escalate to human expert if needed.
10. Verify outputs/outcomes where possible.
11. Save memory and update score/profile.
12. Recommend next workflow or recurring cadence.
## 10. Data and Network Effects
- What new data does this create?
- How does it improve matching?
- How does it improve QX score?
- How does it strengthen the QR identity?
- Does it add supply, demand, proof, or outcomes to the network?
## 11. Outputs and Artifacts
- User-facing artifacts:
- Buyer/admin artifacts:
- Public/shareable artifacts:
- Verified artifacts:
## 12. Approval and Trust Gates
- What requires explicit user approval?
- What requires admin/buyer approval?
- What can be automated safely?
- What must never be automated?
## 13. Business Model
- Free hook:
- Paid SKU:
- Subscription potential:
- Success fee/take rate:
- Enterprise/institution package:
- Marketplace add-on:
## 14. Success Metrics
- User outcome metric:
- Buyer ROI metric:
- Marketplace liquidity metric:
- Retention metric:
- Data/moat metric:
## 15. Implementation Assumptions
- Current primitives usable:
- New primitives needed:
- Third-party integrations needed:
- Manual ops acceptable for v1:
- Risks or hard parts:
```
---
## 8. Internal Workflow Object Shape
```ts
type Workflow = {
id: string
name: string
segment: Array<
| "students"
| "individuals"
| "coaches"
| "freelancers"
| "startups"
| "recruiters"
| "enterprises"
| "institutes"
>
buyerType: "b2c" | "b2b" | "b2b2c" | "marketplace" | "platform"
economicBuyer: string
landingPageAmbition: string
promise: string
tamHypothesis: string
valueRank: number
urgencyTrigger: string
pricing: {
freeHook?: string
oneTime?: string
subscription?: string
successFee?: string
enterprise?: string
marketplaceTakeRate?: string
}
leadAgent: string
supportingAgents: string[]
humanEscalation?: string[]
currentPrimitives?: string[]
newCapabilitiesNeeded?: string[]
steps: WorkflowStep[]
approvalPoints: ApprovalPoint[]
outputs: ArtifactSpec[]
verifiedArtifacts?: ArtifactSpec[]
memoryWritten: string[]
qxSignalsUpdated: string[]
networkEffects: string[]
successMetrics: string[]
}
```
---
## 9. Product Positioning
Old framing:
> GrowQR has resume, interview, roleplay, matching, courses, Q-score, and coaches.
Better framing:
> GrowQR is an adaptive opportunity network where every person has a trusted QR identity, every ambition gets an AI agent squad, every important moment can escalate to a human expert, and every outcome strengthens the matching graph.
The workflows are how users buy outcomes. The QR identity, QX score, verified achievements, expert marketplace, and matching graph are how GrowQR compounds value across the whole market.

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,584 @@
**GrowQR**
**MARKETPLACE**
**DEVELOPER BRD — TECHNICAL SPECIFICATION**
Career Services Platform • Verified Providers • 5 Delivery Formats • v1.0 • March 2026
| Marketplace Microservice This document contains specifications, business logic, and acceptance criteria required for development. |
| :---: |
| Document Title | Marketplace — Developer BRD Technical Specification |
| :---- | :---- |
| Version | 1.0 — March 2026 |
| :---- | :---- |
| Service Type | Standalone Microservice — Career Services Supply Layer |
| :---- | :---- |
| Provider Types | GrowQR-Certified Coaches | Verified Senior Users | Corporate Firms | GrowQR In-House |
| :---- | :---- |
| Delivery Formats | Live 1:1 Video | Async Review | Group Workshop | Done-For-You | Retainer Package |
| :---- | :---- |
| Pricing Model | Provider sets price freely — GrowQR takes commission % (rate TBD — business decision pending) |
| :---- | :---- |
| Discovery | Open browsing \+ Pathway-triggered smart recommendations |
| :---- | :---- |
| Mentors Relationship | Marketplace is the supply layer. Mentors (11-service) \= curated subset drawn from Marketplace providers. |
| :---- | :---- |
| Innovation Features | Supply Seeding | Outcome Guarantee | Q-Score Verified Results | Group Demand Aggregation | Pre-Booking Engine |
| :---- | :---- |
| 1\. EXECUTIVE SUMMARY |
| :---- |
GrowQR Marketplace is a verified career services platform where professionals offer paid services to GrowQR users. It operates as a standalone microservice and serves as the supply layer for the entire GrowQR platform — including the Mentors service within the 11-service pathway model.
Unlike generic freelance marketplaces, every provider on GrowQR Marketplace is validated and approved before going live. Services are directly aligned to career development needs: interview preparation, resume building, social branding, job search coaching, domain guidance, and more.
Users discover providers through open browsing and through intelligent recommendations surfaced by the Pathways engine based on their Q-Score gaps and current cycle phase.
## **1.1 Marketplace vs Mentors — Architectural Relationship**
| Marketplace and Mentors are not the same thing. Marketplace is the full open platform of verified providers. Mentors is a curated, GrowQR-selected subset of Marketplace providers that is surfaced inside a users active pathway cycle. A provider must first be listed on Marketplace before they can be selected as a Mentor. |
| :---- |
| Dimension | Marketplace | Mentors (11-Service) |
| :---- | :---- | :---- |
| Access | Any verified GrowQR user can browse and book freely | Surfaced by Pathways engine at scheduled cycle touchpoints |
| Provider selection | User chooses any available provider | GrowQR curates and recommends based on pathway match |
| Pricing | Provider sets price; GrowQR takes commission | May be subsidised or coin-redeemable within pathway |
| Booking trigger | User-initiated at any time | Pathway-triggered (monthly touchpoint) |
| Provider pool | All validated Marketplace providers | Curated subset hand-picked by GrowQR from Marketplace |
| Session format | All 5 formats available | Primarily live 1:1 and retainer |
| 2\. PROVIDER TYPES & VALIDATION |
| :---- |
Four provider types are permitted on the Marketplace. All must complete GrowQRs validation process before their profile goes live. Validation criteria vary by provider type.
| Provider Type | Description | Validation Requirements |
| :---- | :---- | :---- |
| GrowQR-Certified External Coach | Independent coaches and mentors certified by GrowQR through an internal accreditation process | Application \+ credentials review \+ sample session evaluation \+ GrowQR certification badge awarded |
| Verified Senior User | Experienced GrowQR platform users (typically 5+ years in their domain) who apply to offer services to peers | Minimum Q-Score thresholds \+ experience verification \+ portfolio review \+ GrowQR approval |
| Corporate / Institutional Provider | Coaching firms, HR consultancies, universities, and training organisations offering team or individual services | Business registration \+ service catalogue review \+ compliance check \+ signed provider agreement |
| GrowQR In-House Expert | GrowQR staff or contracted experts offering services directly on the platform | Internal onboarding only — no external validation required |
## **2.1 Provider Validation Flow**
| Step | Action | System Behaviour | Outcome |
| :---- | :---- | :---- | :---- |
| 1 | Provider submits application | Application form: personal/company info, domain expertise, credentials, work samples, service types intended | Application record created with status: Pending Review |
| 2 | GrowQR review | Internal team reviews credentials, samples, and profile completeness | Status updated: Under Review |
| 3 | Sample session (coaches only) | Applicant completes a 20-min sample session with a GrowQR reviewer | Session scored on rubric; pass/fail recorded |
| 4 | Decision | GrowQR approves or rejects | Approved: profile activated. Rejected: reason sent, reapplication permitted after 30 days |
| 5 | Profile build | Provider builds their Marketplace profile, sets services, prices, availability | Profile status: Draft until published |
| 6 | Go live | Provider publishes profile | Profile visible to all users; eligible for pathway recommendations |
## **2.2 Provider Profile Contents**
* Full name and professional photo
* Domain expertise tags (e.g. Software Engineering, Product Management, Sales, Marketing)
* Years of experience and career highlights
* Services offered: format, duration, price per service
* Portfolio: sample work, case studies, testimonials
* Certifications and credentials (verified badge shown if GrowQR-certified)
* Availability calendar: real-time slots for live sessions
* Response time indicator for async services
* Rating and review history (post-launch, populated by completed bookings)
* Total sessions completed and repeat booking rate
| 3\. SERVICE CATEGORIES |
| :---- |
Marketplace services are organised into categories aligned to GrowQRs career development modules. Providers list their services under one or more categories. The Pathways engine uses category tags to surface relevant provider recommendations.
| Category | Services Included | GrowQR Module Alignment |
| :---- | :---- | :---- |
| Interview Preparation | Mock interviews, interview strategy coaching, role-specific interview practice, pre-interview briefing sessions | Upskills — Practice / Interview Service |
| Resume & Cover Letter | Resume review, resume rewrite, cover letter writing, ATS optimisation, LinkedIn profile review | Opportunity — Resume & Cover Letter Service |
| Social & Personal Branding | LinkedIn profile overhaul, content strategy, personal brand audit, thought leadership coaching | Opportunity — Social Branding Service |
| Career Coaching | Career direction coaching, career change strategy, goal-setting sessions, career identity clarity | Pathways — General Guidance |
| Job Search Strategy | Job search planning, application strategy, recruiter outreach coaching, salary negotiation prep | Opportunity — Job Matchmaking |
| Domain & Industry Guidance | Sector-specific career advice, industry entry coaching, domain skill gap guidance | Pathways — Domain Mapping |
| Skills Development Coaching | Personalised skill-building plans, learning roadmap sessions, soft skills coaching | Upskills — Courses / Roleplay |
| Entrepreneurship & Business | Startup mentoring, business validation sessions, founder coaching, side-hustle guidance | Pathways — Entrepreneurial Builder Archetype |
| Academic & Graduate Guidance | University application coaching, graduate programme strategy, first-job preparation | Pathways — Student Persona |
| 4\. FIVE SERVICE DELIVERY FORMATS |
| :---- |
Every service listed on Marketplace must be assigned to one of five delivery formats. Each format has distinct booking flows, delivery requirements, and completion criteria.
| ▶ FORMAT 1: LIVE 1:1 VIDEO SESSION |
| :---- |
| User books a specific time slot from the providers availability calendar |
| Duration options set by provider: 20 min / 30 min / 45 min / 60 min / 90 min |
| Session conducted via GrowQRs integrated video tool (or provider-specified link) |
| Booking confirmed: calendar invite sent to both parties; reminder notifications at 24hr and 1hr before |
| Session recording: optional, requires consent from both parties before session starts |
| Post-session: provider submits session notes within 24hrs; user prompted to leave a review |
| Completion triggered: when session end time is reached or provider marks as complete |
| Cancellation policy: enforced per platform rules (see Section 8\) |
| ⏱ FORMAT 2: ASYNC REVIEW |
| :---- |
| User submits material for review: resume, LinkedIn profile URL, cover letter, portfolio, or other document |
| Provider has a defined turnaround time (set at listing creation): 24hrs / 48hrs / 72hrs |
| Provider delivers feedback as: annotated document, written report, or recorded video walkthrough |
| User receives notification when feedback is delivered |
| User can submit one follow-up question within 48hrs of receiving feedback (included in service) |
| Completion triggered: when provider marks delivery as complete |
| Suitable for: Resume reviews, LinkedIn audits, portfolio feedback, cover letter reviews |
| 👥 FORMAT 3: GROUP SESSION / WORKSHOP |
| :---- |
| Provider creates a group session with defined: topic, date/time, max participants (cap set by provider), price per seat |
| Users browse upcoming sessions and book individual seats |
| Minimum participant threshold: provider sets minimum number required for session to run (e.g. 3 of 10 seats) |
| If minimum not met 24hrs before session: session cancelled, all users refunded automatically |
| Session conducted via GrowQRs integrated group video tool |
| Session recording available to all attendees for 7 days post-session (default) |
| Post-session: all attendees prompted to review; provider receives aggregate rating |
| Suitable for: Industry panels, skill workshops, cohort coaching, webinars |
| ✅ FORMAT 4: DONE-FOR-YOU SERVICE |
| :---- |
| Provider delivers a completed work product on behalf of the user |
| User submits brief: role target, key achievements, tone preferences, and any existing materials |
| Provider sets delivery timeline at listing creation: 3 days / 5 days / 7 days |
| Provider submits first draft to user via platform messaging |
| User entitled to: 1 revision request within 5 days of first draft delivery |
| Final delivery marked complete by user or auto-completed after 5 days of no response |
| Suitable for: Resume writing, cover letter writing, LinkedIn profile rewrite, bio writing |
| Quality review applies to this format (see Section 8 — Dispute Resolution) |
| 📅 FORMAT 5: RETAINER / MULTI-SESSION PACKAGE |
| :---- |
| Provider offers a structured package: defined number of sessions over a defined period |
| Examples: 4 sessions over 4 weeks / 8 sessions over 2 months / 12 sessions over 3 months |
| Full package price paid upfront at booking; provider cannot change price after booking |
| Scheduling: individual sessions booked by user within the package period using providers availability |
| Unused sessions: if package period expires with unused sessions, partial refund issued per platform policy |
| Suitable for: Ongoing career coaching, job search accountability, skill development programmes |
| This format feeds directly into the Mentors (11-service) model for Tier 3 pathway users |
| 5\. PRICING & COMMISSION MODEL |
| :---- |
| Commission rate is a business decision pending final approval. The BRD specifies the commission architecture and enforcement logic. The actual percentage must be confirmed by the business team before development of the payments module. |
| :---- |
## **5.1 Pricing Model**
Providers set their own prices freely for all services and packages. GrowQR does not restrict pricing. The platform takes a commission percentage from each completed transaction. This model follows the Fiverr/Upwork approach and incentivises providers to price competitively.
| Pricing Rule | Detail |
| :---- | :---- |
| Provider sets price | No minimum or maximum enforced by platform at v1. Provider enters price at service listing creation. |
| Price displayed to user | User sees the full price inclusive of all platform fees. No hidden charges. |
| Commission deducted | GrowQR commission deducted from provider payout at the point of transaction completion. Rate: TBD. |
| Provider payout | Net amount (price minus commission) transferred to provider. Payout schedule: TBD by business team. |
| Currency | Platform handles transactions in the users regional currency. Currency conversion logic: TBD. |
| Refunds | Refund amount returned to user in full. GrowQR absorbs commission on refunded transactions. |
| Package pricing | Retainer packages priced as a single total. Commission applied to full package value at booking. |
## **5.2 Commission Architecture**
| Commission Component | Specification |
| :---- | :---- |
| Commission rate | TBD — Business decision pending. To be confirmed before payments module development. |
| Commission trigger | Commission deducted when: session marked complete / async delivery accepted / done-for-you final delivery confirmed |
| Dispute hold | If dispute raised, commission held in escrow until resolution. Released to GrowQR on dispute closure. |
| Refund handling | On full refund: GrowQR absorbs commission. On partial refund: commission recalculated on net completed value. |
| Provider dashboard | Provider sees: gross earnings, commission deducted, net payout, pending transactions, payout history |
| 6\. DISCOVERY & RECOMMENDATION ENGINE |
| :---- |
Users find Marketplace providers through two complementary mechanisms: open browsing with search and filters, and intelligent recommendations surfaced by the GrowQR Pathways engine based on Q-Score gaps and current pathway cycle phase.
## **6.1 Open Browsing**
* Marketplace homepage: featured providers, recently added, top-rated, trending by category
* Search bar: free-text search by provider name, skill, service type, or keyword
* Filter panel: Category, Delivery format, Price range, Rating (min stars), Availability (date range), Provider type (certified/verified/corporate/in-house), Duration
* Sort options: Relevance, Price (low to high / high to low), Rating, Most booked, Newest
* Provider card view: photo, name, top category, rating, price from, verified badge, quick-book button
* Provider profile page: full details, all services listed, availability calendar, reviews, portfolio
## **6.2 Pathway-Triggered Smart Recommendations**
* Pathways engine analyses users current Q-Score gaps and active cycle phase
* Matches gaps to Marketplace service categories and provider specialisms
* Surfaces up to 3 recommended providers per relevant category at the right cycle moment
* Recommendation card shown in: Pathway dashboard, weekly cycle task list, and Marketplace homepage (personalised section)
* Example triggers:
* User Q-Score CQm below target → recommend Interview Prep or Social Branding providers
* User entering Job Matching phase (Week 4+) → recommend Resume & Cover Letter providers
* User archetype: Entrepreneurial Builder → surface Entrepreneurship & Business coaching providers
* Users pathway milestone: first interview booked → recommend pre-interview 1:1 session
* Pathway recommendations are suggestions only — user is never forced to book and can dismiss
## **6.3 Mentors Pool Selection**
* GrowQR internal team curates the Mentors pool from active, high-rated Marketplace providers
* Selection criteria: minimum rating threshold, minimum sessions completed, active availability, domain alignment to GrowQR archetypes
* Mentors pool reviewed and updated monthly
* Providers are not informed of their Mentor pool status — it does not change their Marketplace listing
* When Pathways engine surfaces a Mentor touchpoint in a users cycle, it draws exclusively from the Mentors pool
| 7\. BOOKING & SESSION MANAGEMENT |
| :---- |
## **7.1 Booking Flow**
| Step | User Action | System Response | Data Captured |
| :---- | :---- | :---- | :---- |
| 1 | User selects service from provider profile | Display service details, price, available slots (live) or turnaround time (async) | Service ID, User ID |
| 2 | User selects slot / submits brief | Live: calendar slot picker. Async/Done-For-You: brief submission form. Group: seat selection. | Slot / brief / seat preference |
| 3 | Payment | User completes payment. Amount shown in full before confirmation. | Payment intent created; transaction ID |
| 4 | Confirmation | Booking confirmed. Calendar invite sent (live sessions). Confirmation email to both parties. | Booking ID, status: Confirmed |
| 5 | Delivery | Provider delivers service per format requirements | Completion event sent to system |
| 6 | Completion | User confirms receipt (or auto-completed per format rules) | Status: Completed; commission triggered |
| 7 | Review | User prompted to leave rating and written review (optional but encouraged) | Rating, review text, timestamp |
## **7.2 Booking States**
| State | Condition | System Behaviour |
| :---- | :---- | :---- |
| Pending | Payment initiated but not confirmed | Hold slot/seat; release if payment not confirmed within 10 minutes |
| Confirmed | Payment successful | Send confirmations; add to providers schedule; notify user |
| In Progress | Session started or delivery underway | Timer active for live sessions; turnaround clock active for async |
| Delivered | Provider marks delivery complete | Notify user; start 5-day acceptance window (async/done-for-you) |
| Completed | User confirms or acceptance window expires | Release commission; prompt review; update provider stats |
| Disputed | User raises dispute before completion | Hold commission; escalate to GrowQR review team |
| Cancelled | Cancelled by user or provider per policy | Refund processed per cancellation policy; slot released |
| No-Show | Provider does not attend live session | Auto-refund issued; provider strike recorded |
## **7.3 Cancellation Policy**
| Cancellation Timing | User Refund | Provider Payout |
| :---- | :---- | :---- |
| More than 24hrs before live session | Full refund | No payout |
| Less than 24hrs before live session | 50% refund | 50% payout (late cancellation fee) |
| No-show by user | No refund | Full payout to provider |
| No-show by provider | Full refund \+ platform credit | No payout \+ strike recorded |
| Async/Done-For-You: cancelled before provider starts | Full refund | No payout |
| Async/Done-For-You: cancelled after provider starts | No refund | Full payout |
| Group session: cancelled by platform (min not met) | Full refund to all attendees | No payout to provider |
| 8\. QUALITY ASSURANCE & DISPUTE RESOLUTION |
| :---- |
GrowQR operates a two-layer quality model: proactive quality review (before and during provider listing) and reactive dispute resolution (after a service is delivered). Both mechanisms are required at v1, particularly given the Done-For-You service format.
## **8.1 Proactive Quality Controls**
| Control | Description | Applies To |
| :---- | :---- | :---- |
| Provider validation | All providers pass GrowQRs approval process before any service goes live | All provider types |
| Sample session review | Coaches and mentors complete a graded sample session before certification | GrowQR-certified coaches |
| Listing review | All service listings reviewed by GrowQR team before publishing. Listings that misrepresent scope rejected. | All service formats |
| Ongoing rating monitoring | Providers with average rating below 3.5 stars (from minimum 5 reviews) flagged for review | All providers |
| Dispute rate monitoring | Providers with dispute rate above 10% of total sessions placed on probation and reviewed | All providers |
| Re-validation | Providers inactive for 6+ months must re-validate before re-activating their listing | All providers |
## **8.2 Dispute Resolution Process**
| Step | Timeframe | Action |
| :---- | :---- | :---- |
| 1\. User raises dispute | Within 5 days of delivery | User selects dispute reason from defined list: Service not delivered / Quality significantly below description / Provider no-show / Other |
| 2\. System holds commission | Immediate | Commission held in escrow. Provider notified of dispute. |
| 3\. Provider responds | Within 48hrs | Provider submits response and any supporting evidence via platform messaging |
| 4\. GrowQR review | Within 3 business days | GrowQR review team assesses dispute, evidence, and delivery record |
| 5\. Resolution | Within 5 business days total | GrowQR issues decision: Full refund / Partial refund / No refund \+ commission released to provider |
| 6\. Appeals | Within 48hrs of decision | Either party may appeal once. Final decision issued within 3 additional business days. No further appeals. |
## **8.3 Dispute Reasons Defined**
* Service not delivered: Provider did not deliver within stated timeframe and did not communicate
* Quality significantly below description: Delivered work materially does not match the service listing
* Provider no-show: Live session not attended by provider without prior notice
* Scope mismatch: Provider delivered something outside the agreed service scope
* Technical failure: Session could not proceed due to platform technical issue (GrowQR liability — auto-refund)
## **8.4 Provider Strike System**
| Strike Event | Action |
| :---- | :---- |
| 1 no-show | Warning issued. Recorded on provider account. |
| 2 no-shows OR 1 upheld dispute | Formal warning. 7-day listing suspension. Mandatory response to GrowQR review team. |
| 3 no-shows OR 2 upheld disputes | Listing suspended. Full re-validation required before reinstatement. |
| 4 strikes of any type | Permanent removal from Marketplace. Provider cannot reapply. |
| 9\. INTEGRATION WITH GROWQR PLATFORM |
| :---- |
| Integrated Service | Data Shared | Direction | Purpose |
| :---- | :---- | :---- | :---- |
| Pathways Service | User Q-Score gaps, current cycle phase, archetype | Pathways → Marketplace | Drives pathway-triggered provider recommendations |
| Pathways Service — Mentors | Curated mentor pool (provider IDs, domain tags, archetypes) | Marketplace → Pathways | Feeds the Mentors touchpoint in pathway cycles |
| Wallet / Rewards | Coin balance, transaction events | Marketplace → Wallet | Enables coin-subsidised bookings |
| Notification Service | Booking confirmations, reminders, delivery alerts, dispute updates | Marketplace → Notify | Push, email, and in-app notifications for all booking events |
| Dashboard Service | Bookings count, sessions completed, providers reviewed | Marketplace → Dashboard | Updates users activity summary and achievement tracking |
| Assessment Service | Q-Score gap profile | Assessment → Marketplace | Used by recommendation engine to match service category to skill gaps |
| User Profile Service | Verified user status, Q-Score profile, pathway tier | Profile → Marketplace | Controls access; verifies eligibility to book services |
| 10\. INNOVATION FEATURES — MARKET FAILURE PREVENTION |
| :---- |
Five structural innovations are built into the Marketplace to prevent the cold start problem and drive sustainable supply-demand balance. These features are first-principles differentiators — no competing career marketplace offers all five simultaneously.
| The cold start problem is the primary cause of marketplace failure: providers will not list if there are no users, and users will not come if there are no providers. Each innovation below directly addresses a specific failure mode. |
| :---- |
## **10.1 Supply Seeding from GrowQRs Own Platform**
Problem solved: Empty marketplace at launch — no providers, no trust signals, no bookings.
GrowQRs own Tier 3 Premium users who complete their pathway and achieve a verifiable outcome (job placement, promotion, career pivot) are the first provider candidates. They have three things no external recruit has: a verified GrowQR success story, measurable Q-Score improvement data, and platform credibility.
**How it works:**
* System monitors pathway completions and outcome events (job landed, promotion recorded, career pivot confirmed)
* Users who meet the threshold (pathway completed \+ Q-Score improvement of 15+ points \+ outcome verified) are flagged as Provider Candidates
* GrowQR sends a targeted invitation: “You went from Q-Score 45 to 78 and landed a Senior PM role in 3 months. Help others do the same — earn from your experience.”
* Invited users enter a fast-track validation flow (abbreviated — platform activity serves as credential verification)
* First cohort of providers seeded before public Marketplace launch
**System Requirements:**
* Pathway Service must emit outcome events to Marketplace microservice
* Candidate flagging logic: pathway\_completed \= true AND q\_score\_delta ≥ 15 AND outcome\_event received
* Fast-track provider application flow: reduced steps, platform data pre-fills credentials
* Provider profile auto-populates: Q-Score improvement stats, pathway completed badge, outcome verified badge
## **10.2 Outcome Guarantee Tier**
Problem solved: User trust — why pay for a service when I dont know if it will work?
Providers who opt in to the Outcome Guarantee tier commit to a defined, measurable outcome for the user. If the outcome is not achieved within the agreed timeframe, the user receives a partial refund. This is structurally impossible on any other career marketplace because no other platform can measure outcomes the way GrowQR can via Q-Scores.
**Outcome types by service category:**
| Service Category | Outcome Definition | Timeframe | Refund if Unmet |
| :---- | :---- | :---- | :---- |
| Interview Preparation | User receives at least 1 interview invitation within 30 days of session | 30 days post-session | 50% refund |
| Resume & Cover Letter | Users resume ATS score improves by defined threshold (measured in-platform) | Immediate on delivery | Full refund |
| Social Branding | Users LinkedIn profile view count increases by 20%+ within 30 days | 30 days | 50% refund |
| Career Coaching | User Q-Score in target domain improves by 10+ points within 60 days | 60 days | 50% refund |
| Skills Development | User Q-Score in coached skill area improves by 8+ points within 45 days | 45 days | 50% refund |
**System Requirements:**
* Provider opts in at service listing level — not all services must be Outcome Guaranteed
* Outcome Guarantee badge displayed prominently on provider card and service listing
* System tracks outcome trigger events per booking: interview invitations, Q-Score reassessment results, LinkedIn analytics sync
* Automated outcome check at timeframe expiry: if outcome event not detected → refund triggered automatically
* Provider payout held in partial escrow for outcome guarantee period
* Providers with Outcome Guarantee badge ranked higher in search results and pathway recommendations
* New DB fields required: outcome\_guarantee (BOOL), outcome\_type, outcome\_timeframe\_days, outcome\_refund\_pct on marketplace\_services table
## **10.3 Q-Score Verified Results on Provider Profiles**
Problem solved: Fake or unverifiable reviews — the standard 5-star system is gamed on every marketplace.
Because GrowQR measures Q-Scores before and after every service interaction, provider profiles can display objective, platform-verified outcome data that no external marketplace can replicate. This makes GrowQRs social proof structurally defensible.
**What is displayed on each provider profile:**
* Average Q-Score improvement across all clients (e.g. “Clients improved their CQm by an average of 18 points”)
* Q-Score improvement breakdown by domain (per service category)
* Number of verified Q-Score measurements (sample size shown for credibility)
* Comparison badge: “Top 10% of Interview Prep providers by client Q-Score improvement”
* Timeline chart: client Q-Score trajectory before and after working with this provider
**System Requirements:**
* Q-Score delta calculated per booking: compare users relevant Q-Score at booking date vs next reassessment date
* Attribution window: Q-Score improvement attributed to provider if reassessment occurs within 60 days of session completion
* Minimum sample size: Q-Score stats shown only after provider has 3+ completed bookings with Q-Score data
* Privacy: Q-Score data displayed as aggregated averages only — no individual user data exposed on provider profile
* New DB table required: marketplace\_qscore\_outcomes (booking\_id, provider\_id, q\_score\_name, score\_before, score\_after, delta, measurement\_date, attributed BOOL)
* Provider profile API must include q\_score\_stats object in response
## **10.4 Group Session Demand Aggregation Engine**
Problem solved: Providers fear empty calendars; individual booking volumes too low to sustain a providers time investment early in the platform lifecycle.
The Pathways engine actively aggregates demand for group sessions by matching pathway cycle phases across users. When a provider posts a group session, GrowQR pushes targeted notifications to all users whose current pathway cycle and Q-Score gaps align with that sessions topic — filling seats without the provider needing to do any marketing.
**How it works:**
* Provider creates a group session: topic, category, date/time, price per seat, max/min participants
* System identifies all active pathway users whose: current cycle week is 24 AND service category matches session topic AND Q-Score gap in relevant domain is ≥15 points
* Targeted push notification sent to matched users: “Based on your pathway, this session is recommended for you this week”
* Session also surfaced in weekly cycle task list as a recommended touchpoint
* Provider dashboard shows: seats filled, demand score (how many users were notified vs booked)
* If session reaches minimum participants early: “Almost full” urgency indicator shown to remaining matched users
**System Requirements:**
* Group session matching query: JOIN pathway\_weekly\_cycles \+ marketplace\_services on category \+ q\_score\_gap threshold
* Notification Service integration: targeted push/email per matched user with session details and booking link
* Pathway engine must expose current\_week and gap\_categories per active user for matching query
* Demand score tracking: notifications\_sent vs bookings\_converted per group session (for provider analytics)
## **10.5 Pre-Booking Engine**
Problem solved: Users disengage before they reach the stage where Marketplace is most valuable; providers have unpredictable and lumpy demand.
The Pre-Booking Engine allows users to reserve a provider slot in advance — at the moment the pathway cycle predicts they will need it — with no charge until 48 hours before the session. This locks future demand, fills provider calendars weeks in advance, and keeps users committed to their pathway progression.
**How it works:**
* When user activates a pathway, Pathways engine calculates future high-value Marketplace moments based on the weekly cycle schedule
* At those predicted moments (e.g. Week 3: user entering interview phase), system surfaces: “Youll be ready for interview prep in 2 weeks. Book a top-rated coach now — no charge until 48hrs before.”
* User selects provider and slot — booking is held with zero payment captured
* 48 hours before session: payment captured automatically from saved payment method. User notified.
* Cancellation before 48hr window: no charge, slot released
* Cancellation within 48hr window: standard cancellation policy applies
* Provider sees pre-bookings in calendar as “Pending Payment” — slot is held and cannot be double-booked
**System Requirements:**
* New booking status: pre\_booked (slot held, payment not yet captured)
* Payment capture job: runs every hour, captures payment for pre\_booked sessions where slot\_datetime is within 48hrs
* Pathway engine must emit pre-booking suggestion events with predicted\_need\_week and service\_category
* Provider availability: pre\_booked slots shown as held in availability calendar — not available for other bookings
* User payment method must be saved at pre-booking time (card saved, no charge yet)
* New DB fields on marketplace\_bookings: booking\_type (standard/pre\_booked), payment\_capture\_scheduled\_at, payment\_captured\_at
| 10.6 ADDITIONAL DATABASE FIELDS — INNOVATION FEATURES |
| :---- |
| Table | Additional Fields for Innovation Features |
| :---- | :---- |
| marketplace\_services | outcome\_guarantee (BOOL default false), outcome\_type (enum), outcome\_definition (text), outcome\_timeframe\_days (INT), outcome\_refund\_pct (INT 0-100), outcome\_escrow\_days (INT) |
| marketplace\_bookings | booking\_type (enum: standard/pre\_booked), payment\_capture\_scheduled\_at (TIMESTAMP nullable), payment\_captured\_at (TIMESTAMP nullable), outcome\_check\_due\_at (TIMESTAMP nullable), outcome\_achieved (BOOL nullable) |
| marketplace\_providers | is\_seeded\_provider (BOOL), seed\_pathway\_id (FK nullable), seed\_q\_score\_delta (INT nullable), fast\_track\_validated (BOOL), q\_score\_avg\_improvement (DECIMAL), q\_score\_sample\_size (INT) |
| marketplace\_qscore\_outcomes | outcome\_id (PK), booking\_id (FK), provider\_id (FK), user\_id (FK), q\_score\_name, score\_before (INT), score\_after (INT), delta (INT), measurement\_date (DATE), attributed (BOOL), attribution\_window\_days (INT) |
| marketplace\_group\_demand | demand\_id (PK), service\_id (FK), users\_notified (INT), users\_booked (INT), notification\_sent\_at (TIMESTAMP), cycle\_week\_match (INT), gap\_category (VARCHAR) |
| 11\. ACCEPTANCE CRITERIA |
| :---- |
| \# | Acceptance Criterion | Pass / Fail |
| :---- | :---- | :---- |
| **1** | Provider application flow completes successfully for all four provider types. Application record created with correct status transitions: Pending → Under Review → Approved / Rejected. | \[ \] PASS \[ \] FAIL |
| **2** | Approved providers can build a profile and publish services. Unapproved providers cannot publish. Rejected providers cannot reapply for 30 days. | \[ \] PASS \[ \] FAIL |
| **3** | All five delivery formats (Live 1:1, Async, Group, Done-For-You, Retainer) can be created as service listings by providers and booked by users. | \[ \] PASS \[ \] FAIL |
| **4** | Open browsing returns correctly filtered and sorted provider results. All filter options (category, format, price, rating, availability, provider type) function correctly. | \[ \] PASS \[ \] FAIL |
| **5** | Pathway-triggered recommendations surface up to 3 relevant providers per category based on user Q-Score gaps and active cycle phase. Recommendations appear in Pathway dashboard and weekly cycle task list. | \[ \] PASS \[ \] FAIL |
| **6** | Booking flow completes for all five formats: payment processed, booking confirmed, calendar invite sent (live sessions), brief received (async/done-for-you), seat assigned (group). | \[ \] PASS \[ \] FAIL |
| **7** | All booking state transitions function correctly: Pending → Confirmed → In Progress → Delivered → Completed. | \[ \] PASS \[ \] FAIL |
| **8** | Cancellation policy enforced: correct refund and payout amounts calculated for each cancellation scenario. | \[ \] PASS \[ \] FAIL |
| **9** | Provider no-show triggers automatic full refund and strike recorded on provider account. | \[ \] PASS \[ \] FAIL |
| **10** | Dispute flow completes end-to-end: user raises dispute, commission held in escrow, provider notified, GrowQR review team receives escalation, resolution issued within 5 business days. | \[ \] PASS \[ \] FAIL |
| **11** | Strike system enforced: correct action taken at 1, 2, 3, and 4 strike thresholds. | \[ \] PASS \[ \] FAIL |
| **12** | Commission deducted correctly at transaction completion. Provider payout calculated as gross minus commission. Commission rate field configurable by admin (pending business decision on rate). | \[ \] PASS \[ \] FAIL |
| **13** | Group session auto-cancels and refunds all attendees if minimum participant threshold not met 24hrs before session. | \[ \] PASS \[ \] FAIL |
| **14** | Retainer packages: full amount charged at booking. Partial refund issued for unused sessions when package period expires. | \[ \] PASS \[ \] FAIL |
| **15** | Mentor pool API endpoint returns correctly curated provider subset. Pathways service can query by archetype and domain tag. | \[ \] PASS \[ \] FAIL |
| **16** | Provider dashboard shows gross earnings, commission deducted, net payout, pending transactions, and payout history accurately. | \[ \] PASS \[ \] FAIL |
| **17** | Review system: users can leave rating and review only after booking is marked Completed. Provider rating average updates correctly. Provider cannot review their own service. | \[ \] PASS \[ \] FAIL |
| **18** | Done-for-you 1-revision entitlement enforced: user can submit one revision request within 5 days of first draft. Second revision requests rejected. | \[ \] PASS \[ \] FAIL |
| **19** | Provider rating monitoring: providers below 3.5 stars (min 5 reviews) flagged in admin dashboard. Providers above 10% dispute rate flagged for review. | \[ \] PASS \[ \] FAIL |
| **20** | Supply Seeding: System correctly identifies Provider Candidates (pathway completed \+ Q-Score delta ≥15 \+ outcome event). Fast-track application flow pre-fills profile from platform data. Seeded provider badge displays on profile. | \[ \] PASS \[ \] FAIL |
| **21** | Outcome Guarantee: Providers can opt in per service listing. Outcome badge displays on provider card and listing. Outcome check job fires at timeframe expiry. Automated refund triggered correctly if outcome not detected. Partial escrow held and released correctly. | \[ \] PASS \[ \] FAIL |
| **22** | Q-Score Verified Results: q\_score\_outcomes table populated correctly with before/after scores attributed within 60-day window. Provider profile displays aggregated Q-Score improvement stats. Stats hidden until minimum 3 bookings with Q-Score data. No individual user data exposed. | \[ \] PASS \[ \] FAIL |
| **23** | Group Demand Aggregation: Matching query correctly identifies users whose cycle week and Q-Score gap align with group session topic. Targeted notifications sent to matched users. Demand score (notified vs booked) tracked per session and visible in provider dashboard. | \[ \] PASS \[ \] FAIL |
| **24** | Pre-Booking Engine: Pre-booked slots held in provider calendar and blocked from other bookings. Payment capture job fires correctly within 48hrs of session time. Cancellations before 48hr window result in zero charge. Pathway engine suggestion events surface pre-booking prompts at correct cycle weeks. | \[ \] PASS \[ \] FAIL |
| DOCUMENT APPROVAL |
| :---- |
| Product Owner | \_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_ Date: \_\_\_/\_\_\_/\_\_\_\_\_\_ |
| :---- | :---- |
| Tech Lead | \_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_ Date: \_\_\_/\_\_\_/\_\_\_\_\_\_ |
| :---- | :---- |
| Status: \[ \] APPROVED — Ready for development \[ \] REVISIONS NEEDED Comments: \_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_ \_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_ |
| :---- |

View File

@@ -0,0 +1,278 @@
**GrowQR**
**PATHWAYS**
**MICROSERVICE SPECIFICATION**
Option A: LinkedIn / Resume-Based • Option B: Premium Psychometric • v4.0 • March 2026
| Pathway Microservice — Development Handover This document defines the business logic, user flows, and acceptance criteria for the Pathways service. |
| :---: |
| Service | Pathways — Career Development Orchestration Engine |
| :---- | :---- |
| Generation Options | Option A: LinkedIn / Resume scan | Option B: Psychometric \+ Q-Score (Premium) |
| :---- | :---- |
| User Tiers | Tier 1: Basic (Free) | Tier 2: Report (One-Time) | Tier 3: Premium (Subscription) |
| :---- | :---- |
| Platforms | LinkedIn— multi-country labour data: India, USA, Europe |
| :---- | :---- |
| Version | 4.0 — March 2026 |
| :---- | :---- |
| 1\. WHAT IS PATHWAYS? |
| :---- |
Pathways is the central orchestration engine of GrowQR. It takes a users background, interests, skills, and goals — and turns them into a personalised career development journey coordinated across all 11 GrowQR services.
**The core question Pathways answers:**
***“What else can I — given my personality, skills, and background — do and achieve in the world?”***
Not just: “What is the next job title in my current career?”
Pathways generates a wide range of career combination options — some expected, some surprising — based on who the user actually is, not just what their CV says. It then activates a structured journey to help them get there.
| What Pathways Does | What Pathways Is Not |
| :---- | :---- |
| Generates multiple career path options from the users profile and questionnaire | A simple job search tool |
| Orchestrates 11 services into weekly development cycles | A course platform or LMS |
| Produces a professional Pathway Report PDF | A static one-time plan |
| Adapts in real-time as Q-Scores improve and activities complete | A rigid 12-month roadmap |
| Surfaces live job market data by region (India, USA, Europe) | A recruitment agency |
| 2\. THE QUESTIONNAIRE FLOW |
| :---- |
Before any pathway is generated — whether Option A or Option B — the user completes a short questionnaire. This is the input layer that drives career combination generation. It is asking about experience, interests, and skills — but GrowQR goes further by combining this with profile data and Q-Scores.
| The questionnaire is designed to take 510 minutes maximum. Questions are conversational, not clinical. The goal is to surface what the user cares about and where they want to go — not to test them. |
| :---- |
**2.1 Questionnaire Structure — Four Steps (Most of it can be taken Linkedin or Resume)**
| STEP 1: PREVIOUS EXPERIENCE |
| :---- |
| What is your current or most recent job title? |
| How many years of professional experience do you have? (Student / 02 years / 35 years / 610 years / 10+ years) |
| Which industry or domain have you worked in most? (dropdown with multi-select) |
| What are 35 things you have done professionally that you are most proud of? (free text, short) |
| STEP 2: INTERESTS & WHAT ENERGISES YOU |
| :---- |
| Which of these activities energise you most? (multi-select from 1215 options e.g. solving complex problems, leading people, building products, creating content, selling ideas, analysing data, coaching others, designing experiences) |
| What topics do you find yourself reading about or watching videos on outside of work? (free text) |
| Do you prefer working independently, in a team, or leading others? (single select) |
| What kind of environment brings out your best work? (e.g. fast-moving startup, large organisation, remote, client-facing) |
| STEP 3: SKILLS |
| :---- |
| What are your top 35 skills? (free text or tag selection from skill bank) |
| Which skills do you most want to develop in the next 12 months? (multi-select) |
| Are there any domains or tools you have taught yourself outside of formal education? (free text) |
| STEP 4: GOALS & DIRECTION |
| :---- |
| Where do you want to be in your career in 13 years? (free text) |
| What matters more to you right now — higher earnings, greater fulfilment, or a balance of both? (slider: 0% earnings / 100% fulfilment ↔ 100% earnings / 0% fulfilment) |
| Is there a specific role, company type, or industry you are aiming for? (optional, free text) |
| What is your biggest career challenge right now? (multi-select: lack of direction / skills gaps / not getting interviews / need to change industry / want to grow faster / starting from scratch) |
**2.2 What the Questionnaire Generates**
Once the four steps are complete, the system combines questionnaire responses with any available profile data (LinkedIn scan or resume) to generate:
* A wide range of career combination options — not just one or two obvious paths, but a broader set of possibilities the user may not have considered
* Each combination shows: role title, domain, match rationale, required skills, salary range (by region), and demand level
* Options are grouped by: Close Match (high overlap with current skills), Adjacent (moderate pivot), and Stretch (ambitious but achievable with development)
* The Visual Career Web is rendered from this output — showing the combinations as an interactive node map
* A Career Identity Statement is generated: 23 sentences summarising the users transferable value
| The questionnaire output feeds both Option A and Option B. For Option A users, it is the primary input. For Option B Premium users, it is combined with the psychometric assessment and full 25 Q-Score results for deeper personalisation. |
| :---- |
| 3\. VISUAL CAREER WEB |
| :---- |
The Visual Career Web is the primary output display of the questionnaire flow. Instead of showing career options as a plain list, it renders them as an interactive node diagram — the users current role or profile at the centre, with recommended career paths radiating outward.
**3.1 How It Works**
* Centre node: users current role or “Your Starting Point” if no current role
* Surrounding nodes: career path combinations grouped by Close Match, Adjacent, and Stretch
* Each node shows on hover or tap: role title, match %, salary range, demand level (High / Medium / Low)
* Clicking a node expands it: skill gaps, top courses, live job links, regional salary chart
* Filter bar: user can adjust weightings (skills match / salary priority / growth potential / interests alignment) — web re-renders
* Colour coding: Green \= high demand, Amber \= medium demand, Grey \= low demand or emerging
* Mobile: full interactive on desktop and tablet; card-stack view on mobile
**3.2 Tier-Gated Behaviour**
| Feature | Tier 1 Basic | Tier 2 Report | Tier 3 Premium |
| :---- | :---- | :---- | :---- |
| Career web visible | Yes — full web | Yes — full web | Yes — full web |
| Node expansion (full detail) | 2 nodes only, rest locked | All nodes | All nodes \+ Q-Score gap mapping |
| Live job links per path | 3 per node | 10 per node | Unlimited real-time |
| Salary data | Range only | Full chart | Full chart \+ regional comparison |
| Pathway activation | Locked — upgrade prompt | 1-month activation | 3 / 6 / 12-month activation |
| 4\. THREE-TIER USER MODEL |
| :---- |
Users enter at any tier. Each tier delivers real value. Higher tiers unlock deeper personalisation and longer pathway activation.
| | Tier 1: Basic | Tier 2: Report | Tier 3: Premium |
| :---- | :---- | :---- | :---- |
| Access | Free — no account required | One-time purchase | Subscription |
| Input | LinkedIn URL or resume upload \+ questionnaire | Same as Tier 1 | Psychometric assessment \+ 25 Q-Scores \+ questionnaire |
| Career Web | Full web, 2 nodes expandable | Full web, all nodes | Full web, all nodes \+ Q-Score mapping |
| Report | 2-section teaser PDF | Full 1416 page PDF | Full PDF, auto-updates as progress made |
| Pathway Activation | None | 1 month — all 11 services | 3 / 6 / 12 months — all 11 services |
| Personalisation | Profile \+ questionnaire | Profile \+ questionnaire | Psychometric \+ Q-Score \+ questionnaire |
| Upgrade Prompt | Purchase Report or start Premium | Upgrade to Premium after 1 month | Ongoing — no further upgrade needed |
| 5\. TWO PATHWAY GENERATION OPTIONS |
| :---- |
Both options activate the full 11-service orchestration engine once a pathway is live. The difference is the depth of input used to personalise the pathway.
| OPTION A: BASIC — LinkedIn / Resume-Based Available to Tier 1, 2 and 3 as starting point • No psychometric required |
| :---- |
| Input: LinkedIn URL or uploaded resume (PDF / DOCX) \+ completed questionnaire (4 steps) |
| Parser extracts: current role, skills, work history, education, certifications, industry |
| Combined with questionnaire responses to generate career combination options |
| Career Identity Statement generated: 23 sentences of transferable value summary |
| Visual Career Web rendered: 35+ career path combinations across Close Match, Adjacent, Stretch |
| Skill gap analysis per path: which skills need development to reach each option |
| 4-week curriculum generated with specific course links mapped to skill gaps |
| Live job postings surfaced per path from regional job platforms |
| Regional labour market data applied: salary, demand, top hiring companies (India / USA / Europe) |
| Full Pathway Report PDF generated for Tier 2 and Tier 3 users |
| 1-month pathway activated for Tier 2\. 3/6/12-month pathway activated for Tier 3\. |
| OPTION B: PREMIUM — Psychometric \+ Q-Score Tier 3 only • Maximum personalisation • Scientifically validated |
| :---- |
| Input: Completed psychometric assessment (1030 questions) \+ all 25 Q-Scores measured \+ questionnaire |
| Big Five personality profiling \+ behavioural analysis (work style, learning style, motivation drivers) |
| Algorithm: 60% psychometric weighting \+ 40% Q-Score weighting \+ questionnaire as contextual layer |
| User sets earnings vs. fulfilment ratio (slider) — adjusts pathway recommendations accordingly |
| Personality Archetype assigned: one of five (see Section 7\) |
| Three pathway options ranked: Primary (85%+ match), Alternative 1 (7585%), Alternative 2 (6575%) |
| User selects and activates one pathway — only one active pathway permitted at any time |
| Full 1416 page Pathway Report PDF generated with archetype analysis, radar charts, and GrowQR branding |
| Weekly cycles generated across all 11 services for 3, 6, or 12 months |
| Adaptive engine: pathway adjusts in real-time as Q-Scores improve and services are completed |
| Monthly Q-Score reassessment; Report PDF auto-updated on significant score changes |
| 6\. 11-SERVICE ORCHESTRATION |
| :---- |
Pathways does not contain the 11 services. It is an orchestration layer that coordinates them through touchpoints. Once a user activates a pathway (Tier 2 or Tier 3), all 11 services are engaged in a structured weekly cycle. Suggestions:
| Service | Primary Skills Built | Cycle Frequency |
| :---- | :---- | :---- |
| 1\. Roleplay (LMS) | Communication, Emotional Intelligence, Influence | Weekly |
| 2\. Interview Practice | Analytical thinking, Communication, Leadership | Weekly |
| 3\. Courses | Technical, Domain, Business, Learning skills | Weekly — heavy in Month 1 |
| 4\. Assessment | All 25 Q-Scores measured | Week 1 baseline; monthly after |
| 5\. Resume & Cover Letter | Updated automatically as skills develop | As skills develop |
| 6\. Social Branding | Reputation, Influence, Networking, Marketing | Bi-weekly |
| 7\. Job Matching | All Q-Scores (matching layer) | Light Month 1; heavy Month 2+ |
| 8\. Events | Networking, Social, Cultural | 12 per month |
| 9\. Networking | Networking, Social, Influence | Weekly Month 1; bi-weekly after |
| 10\. Mentors | Learning, Growth, Vision, Leadership | Monthly sessions |
| 11\. Community | Social, Networking, Reputation | Bi-weekly |
**6.1 Six Weekly Cycle Rules \- Suggestions:**
| Rule | Description |
| :---- | :---- |
| Rule 1: Start with Assessment | Week 1 always begins with Q-Score baseline measurement. Cannot be skipped. |
| Rule 2: Core Services Weekly | Courses, Roleplay, and Interview Practice appear every week throughout the pathway. |
| Rule 3: Support Services Scheduled | Mentors monthly. Community bi-weekly. Networking weekly in Month 1, bi-weekly after. |
| Rule 4: Time Balance | Total weekly commitment: 23 hours. Hard cap: 3.5 hours. Prevents burnout. |
| Rule 5: Progression | Month 1: 60% Learn / 40% Apply. Month 2: 50/50. Month 3+: 30% Learn / 70% Apply. |
| Rule 6: Adaptive | Skipped service \= higher priority next week. Q-Score \+10 points \= advanced content unlocked. |
| 7\. PATHWAY REPORT — PDF SPECIFICATION |
| :---- |
The Pathway Report is a professionally designed PDF document generated for Tier 2 (one-time purchase) and Tier 3 (subscription). Tier 1 receives a 2-section teaser. The report is 1416 pages, full colour, GrowQR branded.
| Section | Title | Contents |
| :---- | :---- | :---- |
| 1 | Your Personality Archetype | Archetype badge, top 5 Q-Scores with radar chart, what motivates you, how you work best |
| 2 | Career Path Recommendations | Primary path (85%+), Alternative 1 (7585%), Alternative 2 (6575%), comparison table |
| 3 | Skill Development Plan | Q-Score gap analysis, top 5 priority skills, course links, milestone checkpoints |
| 4 | Job Market Alignment | Demand indicator, salary range by experience (region-specific), top 15 companies hiring |
| 5 | Weekly Action Plan | Month 1 week-by-week calendar, 11-service touchpoint grid, monthly goals checklist |
| 6 | 11 Services Map | Each service: what it does, when to use, expected outcome |
| 7 | Progress Tracking | Q-Score trend chart, monthly snapshot, milestone checklist, application pipeline |
| 8 | Next Steps | Top 3 immediate actions, support resources, motivational close |
| 8\. FIVE PERSONALITY ARCHETYPES — OPTION B REFERENCE |
| :---- |
Used in Option B (Premium) only. Archetype is assigned based on Q-Score profile after psychometric assessment is complete.
| Archetype | Q-Score Thresholds | Typical Pathways |
| :---- | :---- | :---- |
| Technical Specialist | TQ ≥75, IQ ≥75, XQ ≥70, DQ ≥70 | Software Engineer, Data Scientist, Technical Architect |
| Strategic Leader | StQ ≥75, LdrQ ≥75, VQ ≥70, InQ ≥70, EQ ≥70 | VP/Director, Strategy Consultant, Founder/CEO |
| Creative Innovator | CrQ ≥75, CQx ≥70, IQ ≥70, CQm ≥70 | Product Designer, UX Researcher, Creative Director |
| Sales & Influence Driver | MQ ≥75, InQ ≥75, NQ ≥70, CQm ≥70 | Sales Director, Business Development, Growth Lead |
| Entrepreneurial Builder | GQ ≥75, XQ ≥75, DQ ≥75, AQ ≥70, RQ ≥70 | Founder/Startup, Product Manager, Independent Consultant |
| 9\. SYSTEM CONSTRAINTS |
| :---- |
The following constraints must be enforced by the system at all times:
| \# | Constraint |
| :---- | :---- |
| 1 | Only 1 active pathway permitted per user at any time. Activating a new pathway deactivates the previous. |
| 2 | Pathway switching requires a minimum of 2- 4 weeks completed on the current pathway. |
| 3 | Pathway regeneration is limited to once per calendar month. |
| 4 | Timeline options are fixed: 1 month (Tier 2), or 3 / 6 / 12 months (Tier 3). No custom timelines. |
| 5 | Option B generation requires all 25 Q-Scores to be completed. Partial assessments are rejected. |
| 6 | Career goal input is validated by NLP. Vague goals (e.g. better job) are rejected with a clarification prompt. |
| 7 | Weekly cycle time cap: maximum 3.5 hours of service touchpoints per week. |
| 8 | Questionnaire must be completed before any pathway is generated, regardless of option or tier. |
| 9 | Region is auto-detected on first use. Labour market data served from matching regional dataset. Manual override available. |
| 10 | Generated reports stored for 12 months from creation date. |
| 10\. ACCEPTANCE CRITERIA |
| :---- |
| \# | Acceptance Criterion | Pass / Fail |
| :---- | :---- | :---- |
| **1** | Questionnaire flow completes all 4 steps for all users (Tier 1, 2, and 3). Responses captured correctly. Questionnaire must be completed before pathway generation is triggered. | \[ \] PASS \[ \] FAIL |
| **2** | Career combination options generated from questionnaire \+ profile data. Options grouped correctly into Close Match, Adjacent, and Stretch categories. | \[ \] PASS \[ \] FAIL |
| **3** | Career Identity Statement generated for every user on questionnaire completion. | \[ \] PASS \[ \] FAIL |
| **4** | Visual Career Web renders with correct nodes per combination category. Filter adjustments re-render the web in real-time. Tier-gated content enforced (Tier 1: 2 nodes expandable; Tier 2+: all nodes). | \[ \] PASS \[ \] FAIL |
| **5** | Option A pathway generated correctly from LinkedIn URL or resume upload \+ questionnaire. Skill gap analysis, 4-week curriculum, and live job postings populated per path. | \[ \] PASS \[ \] FAIL |
| **6** | Option B pathway generated using 60% psychometric \+ 40% Q-Score algorithm. Requires all 25 Q-Scores completed. Archetype assigned correctly from Q-Score thresholds. | \[ \] PASS \[ \] FAIL |
| **7** | Three pathway options generated for Option B: Primary (85%+), Alt 1 (7585%), Alt 2 (6575%). Match percentages calculated correctly. | \[ \] PASS \[ \] FAIL |
| **8** | Tier 1: 2-section teaser PDF generated with upgrade CTA. Tier 2 and 3: Full 1416 page Pathway Report PDF generated with all 8 sections and GrowQR branding. Generation time under 5 seconds. | \[ \] PASS \[ \] FAIL |
| **9** | Tier 2: 1-month pathway activated on purchase. All 11 services available. Deactivates after 30 days if not upgraded. | \[ \] PASS \[ \] FAIL |
| **10** | Tier 3: 3/6/12-month pathway active. Weekly cycles follow all 6 generation rules. Adaptive engine adjusts cycle based on Q-Score changes and service completions. | \[ \] PASS \[ \] FAIL |
| **11** | Both Option A and Option B activate full 11-service orchestration on pathway activation. | \[ \] PASS \[ \] FAIL |
| **12** | Regional labour market data served correctly for India, USA, and Europe. Salary, demand, and company data accurate per region. Auto-detection functional with manual override. | \[ \] PASS \[ \] FAIL |
| **13** | All 10 system constraints enforced correctly. | \[ \] PASS \[ \] FAIL |
| **14** | Monthly Q-Score reassessment updates pathway recommendations and triggers report regeneration when score changes by 10+ points. | \[ \] PASS \[ \] FAIL |
| **15** | Google Drive PDF save functions correctly for Tier 3 users (optional feature). | \[ \] PASS \[ \] FAIL |

View File

@@ -0,0 +1,396 @@
**GrowQR**
**SOCIAL BRANDING**
**DEVELOPER BRD — TECHNICAL SPECIFICATION**
Individual Social Branding • Enterprise Social Branding • 4 Platforms • 6 Personas • v1.0 • March 2026
| Social Branding Microservices This document contains specifications, business logic, and acceptance criteria for development. |
| :---: |
| Document Title | Social Branding Service — Developer BRD Technical Specification |
| :---- | :---- |
| Version | 1.0 — March 2026 |
| :---- | :---- |
| Service Type | Standalone Microservice — Part of Opportunity Module |
| :---- | :---- |
| Target Platforms | LinkedIn | Instagram | Twitter/X | YouTube |
| :---- | :---- |
| Target Launch | April 1st — LinkedIn, Instagram, YouTube, Twitter/X , Git |
| :---- | :---- |
| Part 1 | Individual Social Branding — 6 end-goal personas, full automation with approval |
| :---- | :---- |
| Part 2 | Enterprise Social Branding — Company brand presence, governance, multi-platform management |
| :---- | :---- |
| Q-Score Integration | Brand Score (0100) feeds RQx. Q-Score changes trigger automatic profile and content updates. |
| :---- | :---- |
| Data Collection | Method TBD by technical team — BRD specifies data requirements only |
| :---- | :---- |
| PART 1 — INDIVIDUAL SOCIAL BRANDING |
| :---: |
Part 1 covers the Social Branding service for individual GrowQR users. It is a fully automated, AI-managed presence builder across LinkedIn, Instagram, Twitter/X, and YouTube — with user approval at every execution step.
| 1\. SERVICE OVERVIEW — INDIVIDUAL |
| :---- |
The Individual Social Branding service transforms a users professional presence from a passive profile into an active, consistent, and strategically managed brand. The service operates on a Scrape → Analyse → Generate → Approve → Post → Track loop, fully managed by GrowQRs AI layer.
The service is built on five structural pillars drawn from proven social branding principles:
| Pillar | Definition | How GrowQR Implements It |
| :---- | :---- | :---- |
| Consistency | Uniform brand voice, visual style, and messaging across all platforms | AI enforces tone, vocabulary, and visual style rules per persona across all connected platforms |
| Target Audience | Understanding the social habits of the users ideal audience (recruiters, clients, peers, investors) | Audience profile built from users pathway archetype, target role, and Q-Score profile |
| Content Strategy | A defined mix of educational, entertaining, and inspirational content mapped to brand values | 80/20 content model: 80% pre-baked persona toolkit, 20% dynamic AI-generated content |
| Engagement | Active interaction with followers: likes, comments, DMs, connection requests | AI drafts engagement responses; user approves or auto-approves based on engagement rules |
| Platform Selection | Right platforms for the users archetype and target audience | Archetype-conditional platform activation — not all platforms recommended to all users |
## **1.1 The Automation Loop**
| Stage | Action | Human Touch Point |
| :---- | :---- | :---- |
| 1\. Connect | User connects social accounts via OAuth | One-time setup per platform |
| 2\. Scrape / Collect | System collects profile data, post history, engagement metrics, follower data | None — automated |
| 3\. Analyse | AI analyses profile completeness, content performance, audience alignment, Brand Score calculated | User reviews Brand Score dashboard |
| 4\. Generate | AI generates: profile rewrites, content calendar, post drafts, engagement responses | User reviews all generated content |
| 5\. Approve | User approves, edits, or rejects each item in the approval queue | Primary user interaction point |
| 6\. Post / Execute | Approved content scheduled and posted. Profile updates applied. Engagement responses sent. | None — automated post-approval |
| 7\. Track | System monitors: impressions, profile views, follower growth, engagement rate, recruiter search appearances | User reviews weekly analytics dashboard |
| 8\. Feed Back | Performance data feeds Brand Score and RQx Q-Score. Pathway engine updates recommendations. | None — automated |
| 2\. BRAND SCORE — THE SOCIAL Q-SCORE |
| :---- |
Brand Score is a single 0100 metric that measures the strength, consistency, and discoverability of a users professional presence across all connected platforms. It is GrowQRs proprietary social presence measurement and feeds directly into RQx (Reputation Quotient) in the Q-Score engine.
| Brand Score is not a vanity metric. It is calculated from objective, measurable signals. As the user takes actions recommended by the Social Branding service, their Brand Score improves. Brand Score improvement directly improves their RQx Q-Score, which in turn updates their pathway recommendations. |
| :---- |
## **2.1 Brand Score Components**
| Component | Weight | What It Measures |
| :---- | :---- | :---- |
| Profile Completeness | 20% | All profile sections populated, keyword-optimised, and aligned to target role across active platforms |
| Content Consistency | 20% | Posting frequency maintained, tone consistent, visual style uniform across platforms |
| Audience Growth | 15% | Follower/connection growth rate over 30-day rolling window |
| Engagement Rate | 15% | Likes, comments, shares, and saves as a percentage of reach per post |
| Recruiter Visibility | 15% | Profile appearance rate in relevant recruiter and talent searches (LinkedIn primary) |
| Content Quality | 10% | AI-assessed relevance, originality, and alignment to persona content framework |
| Cross-Platform Consistency | 5% | Messaging and voice alignment across all connected platforms |
## **2.2 Brand Score → RQx Integration**
* Brand Score calculated after every platform data sync (example: frequency: daily for LinkedIn, 48hrs for others)
* Brand Score mapped to RQx using a defined conversion formula: RQx contribution \= Brand Score × 0.4 (40% weighting of RQx from Brand Score)
* RQx update event emitted to Assessment Service and Pathways Service on every Brand Score change of 5+ points
* Pathways engine re-evaluates Social Branding touchpoint recommendations on RQx update
* Users Brand Score history stored and displayed as a trend line on the Social Branding dashboard
| 3\. SIX END-GOAL PERSONAS — CONTENT FRAMEWORK |
| :---- |
Every users Social Branding strategy is driven by their end-goal persona. The persona is derived from the users active pathway archetype, target role, and career goal input. Users can switch personas as their goals evolve. Each persona has a defined platform mix, content angle, and posting frequency.
| Platform activation is archetype-conditional. Not all platforms are recommended to all users. The system activates platforms relevant to the users persona and prompts the user to connect them. Users can override and connect any platform manually. |
| :---- |
| PERSONA 1: JOB SEEKER Archetype: All archetypes — active job search phase |
| :---- |
| **Recommended Platforms** LinkedIn (primary), Twitter/X (secondary for tech/creative roles) **Content Angle** Recruiter visibility, skills signalling, open-to-work positioning, achievement highlights **Posting Frequency** LinkedIn: 4x per week. Twitter/X: 3x per week if active. |
| PERSONA 2: CAREER TRANSITIONER Archetype: All archetypes — changing domain or role type |
| :---- |
| **Recommended Platforms** LinkedIn (primary), Instagram (if transitioning to creative/coaching/consulting) **Content Angle** Narrative reframing: connecting past experience to new direction, learning journey documentation **Posting Frequency** LinkedIn: 3x per week. Instagram: 2x per week if active. |
| PERSONA 3: THOUGHT LEADER Archetype: Strategic Leader, Entrepreneurial Builder, Domain Expert |
| :---- |
| **Recommended Platforms** LinkedIn (primary), Twitter/X (primary), YouTube (secondary) **Content Angle** Industry insights, opinion pieces, trend analysis, frameworks and models, contrarian takes **Posting Frequency** LinkedIn: 5x per week. Twitter/X: daily. YouTube: 1x per month minimum. |
| PERSONA 4: DOMAIN EXPERT Archetype: Technical Specialist, Creative Innovator |
| :---- |
| **Recommended Platforms** LinkedIn (primary), GitHub (external link), YouTube (tutorials/walkthroughs) **Content Angle** Deep technical content, how-to posts, case studies, project showcases, certification highlights **Posting Frequency** LinkedIn: 3x per week. YouTube: 2x per month. |
| PERSONA 5: ENTREPRENEUR / FOUNDER Archetype: Entrepreneurial Builder |
| :---- |
| **Recommended Platforms** LinkedIn (primary), Twitter/X (primary), Instagram (brand building), YouTube (storytelling) **Content Angle** Build-in-public content, startup journey, lessons learned, team culture, product milestones **Posting Frequency** LinkedIn: 5x per week. Twitter/X: daily. Instagram: 3x per week. YouTube: 2x per month. |
| PERSONA 6: EXECUTIVE / ENTERPRISE LEADER Archetype: Strategic Leader — VP, Director, C-suite level |
| :---- |
| **Recommended Platforms** LinkedIn (primary), Twitter/X (secondary) **Content Angle** Executive presence: strategic vision, culture and values, industry leadership, org transformation, speaking engagements **Posting Frequency** LinkedIn: 3x per week. Twitter/X: 2x per week. |
| 4\. THE 80/20 CONTENT MODEL |
| :---- |
All content generated by GrowQRs Social Branding service follows an 80/20 split: 80% pre-baked toolkit content and 20% dynamic AI-generated content. This balance ensures consistency and quality (80%) while maintaining relevance and freshness (20%).
## **4.1 80% — Pre-Baked Toolkit**
The pre-baked toolkit is a library of proven content frameworks, post templates, hooks, and evergreen structures mapped to each persona and platform. This content is designed, tested, and maintained by GrowQR. It does not require AI generation — it is filled with user-specific data at execution time.
| Content Type | Description | Persona Applicability |
| :---- | :---- | :---- |
| Achievement Post | Structured template: milestone \+ what it took \+ what you learned. Fills with users real achievements from pathway completions. | All personas |
| Skills Signal Post | Highlights a specific skill or certification. Links to Q-Score improvement data. | Job Seeker, Domain Expert, Career Transitioner |
| Insight Share | Short opinion or observation on an industry trend. Structure: Hook \+ Insight \+ Question to audience. | Thought Leader, Executive, Entrepreneur |
| Career Story Post | Narrative format: where I was \+ what changed \+ where I am now. Used for transitions and milestones. | Career Transitioner, Entrepreneur |
| Project Showcase | Work sample or project result with context. Visual-first for Instagram; text+image for LinkedIn. | Domain Expert, Creative Innovator, Entrepreneur |
| Engagement Prompt | Question or poll to drive comments. Mapped to users domain for relevant audience response. | All personas |
| Weekly Reflection | End-of-week summary: what I worked on, what I learned, whats next. | Thought Leader, Entrepreneur, Executive |
| Company/Role Spotlight | Highlights a company or role the user is targeting or has experience with. Builds recruiter relevance. | Job Seeker, Career Transitioner |
## **4.2 20% — Dynamic Content**
Dynamic content is AI-generated in real-time based on signals from the users platform activity, Q-Score progress, pathway milestones, and trending topics in their domain. This content is fresh, timely, and personalised — it cannot be pre-baked.
* Q-Score improvement post: auto-generated when user improves a Q-Score by 10+ points. Frames the improvement as a professional growth story.
* Pathway milestone post: auto-generated when user completes a course, earns a certificate, or achieves a pathway milestone.
* Trending topic response: AI monitors trending topics in the users domain. Generates a short opinion post when a relevant trend is detected.
* Interview or job application event: auto-generated encouragement and visibility post when user applies for a role or secures an interview (with user consent).
* Engagement response drafts: AI drafts replies to comments on the users posts, maintaining persona tone and voice.
* Profile update trigger: when users Q-Scores or pathway status changes significantly, AI generates updated headline, about section, and skills list for user approval.
## **4.3 Content Calendar Generation Rules**
| Rule | Description |
| :---- | :---- |
| Rule 1: Frequency Enforcement | System enforces minimum posting frequency per persona. If user has not approved content for upcoming slots, system sends reminder 48hrs in advance. |
| Rule 2: Platform Sequencing | Content is not duplicated across platforms. Each platform receives a uniquely formatted version adapted to that platforms style and audience. |
| Rule 3: Content Mix Enforcement | System ensures the 80/20 split is maintained over any 2-week rolling window. Prevents over-reliance on either toolkit or dynamic content. |
| Rule 4: No Auto-Post Without Approval | No content is ever posted without explicit user approval. Auto-approve mode is available as an opt-in setting only. |
| Rule 5: Tone Lock | Once users brand voice is established (after first 2 weeks), tone settings are locked unless user explicitly resets them. |
| Rule 6: Sensitive Topic Filter | AI applies a topic filter before generating content. Posts that touch on politically sensitive, legally risky, or reputationally harmful territory are flagged and not queued for approval. |
| 5\. PLATFORM SPECIFICATIONS — INDIVIDUAL |
| :---- |
## **5.1 LinkedIn**
| Capability | Specification |
| :---- | :---- |
| Profile Analysis | Audit: Headline, About, Experience, Skills, Recommendations, Featured section, Activity. Score each section 0100. Benchmark against target role requirements and top 10% of professionals in same role. |
| Profile Rewrite | AI generates optimised versions of: Headline (3 variants), About section, Experience bullet points (per role), Skills list (mapped to Q-Scores and target JD keywords). User selects and approves. |
| Recruiter Visibility | Keyword gap analysis: identifies terms recruiters search for this role that are missing from profile. Injects keywords into profile sections naturally. |
| Content Posting | Supports: text posts, image posts, document carousels, polls, article links. Content formatted to LinkedIn algorithm best practices (hook in first 2 lines, no external links in body). |
| Connection Strategy | Identifies target connections based on users pathway: target companies, role peers, hiring managers in target domain. AI drafts personalised connection request notes. |
| Engagement Automation | AI drafts comments on posts from target connections and industry leaders. User approves before sending. Builds visibility with relevant audience. |
| Analytics Tracked | Profile views (7-day, 30-day), Search appearances, Post impressions, Engagement rate per post, Connection acceptance rate, Follower growth |
## **5.2 Instagram**
| Instagram is activated for: Career Transitioner (creative/coaching roles), Entrepreneur/Founder, Domain Expert (creative/design roles). Not recommended by default for Technical Specialist or Strategic Leader personas unless user opts in. |
| :---- |
| Capability | Specification |
| :---- | :---- |
| Profile Analysis | Bio, profile photo, link-in-bio, highlight covers, grid aesthetic consistency, story frequency. Score for professional brand alignment. |
| Content Types | Feed posts (static image, carousel), Reels (short-form video), Stories (ephemeral). Each type has distinct content templates in the pre-baked toolkit. |
| Visual Style Consistency | AI enforces visual brand rules: colour palette (derived from users LinkedIn brand colours), font style, filter consistency. Applied to all generated visual templates. |
| Caption Framework | Each caption follows: Hook (first line visible before more) \+ Value (body) \+ CTA (final line) \+ Hashtags (max 5, domain-specific). Hashtag bank maintained per persona. |
| Story Strategy | Stories used for: behind-the-scenes content, quick tips, polls, Q\&As. Frequency: 35 stories per week. Story templates provided per persona. |
| Analytics Tracked | Reach, Impressions, Profile visits, Follower growth, Story views, Reel plays, Link-in-bio clicks, Saves per post |
## **5.3 Twitter / X**
| Twitter/X is targeted for Phase 2 launch. Architecture and data model specified here for development readiness. April 1st launch excludes Twitter/X. |
| :---- |
| Capability | Specification |
| :---- | :---- |
| Profile Analysis | Bio (160 chars), header image, pinned tweet, posting frequency, engagement rate, follower-to-following ratio. |
| Content Types | Short posts (under 280 chars), Threads (multi-tweet narrative), Quote posts (with commentary), Replies (engagement strategy). |
| Thread Framework | Threads used for: insight breakdowns, how-to guides, career lessons, domain deep-dives. Format: Hook tweet \+ 510 body tweets \+ CTA final tweet. |
| Posting Strategy | Optimal posting times calculated per users audience timezone. Threads on weekdays, shorter posts and replies on weekends. |
| Analytics Tracked | Impressions, Engagements, Profile clicks, Link clicks, Follower growth, Thread completion rate |
## **5.4 YouTube**
| Capability | Specification |
| :---- | :---- |
| Channel Analysis | Channel art, About section, playlist structure, video titles and descriptions (SEO), thumbnail consistency, upload frequency, subscriber growth rate. |
| Content Types | Long-form (1020 min): deep dives, case studies, tutorials. Short-form (YouTube Shorts, under 60 sec): tips, quick insights, career advice clips. |
| Video Brief Generation | AI generates video briefs: title (3 variants), hook script (first 30 seconds), chapter outline, description with keywords, tags, thumbnail concept. User records; AI does not generate video. |
| SEO Optimisation | Title keyword analysis, description keyword injection, tag strategy, chapter timestamps. Benchmarked against top-performing videos in users domain. |
| Thumbnail Strategy | AI generates thumbnail design brief: text overlay, colour scheme, facial expression guidance (if talking head). Thumbnail template provided per persona. |
| Upload Frequency | Persona-based targets: Thought Leader (1x/month minimum), Domain Expert (2x/month), Entrepreneur (2x/month). System prompts user when cadence is falling behind. |
| Analytics Tracked | Views, Watch time, Subscriber growth, Click-through rate (thumbnails), Average view duration, Top traffic sources |
| 6\. DATA REQUIREMENTS — INDIVIDUAL |
| :---- |
| Data collection method (API vs scraping vs user-authenticated export) is TBD and left to the technical team. This section specifies what data is required. The technical team must define the collection mechanism, document any legal or rate-limit constraints, and confirm data availability before development of the collection layer. |
| :---- |
| Platform | Data Required | Frequency |
| :---- | :---- | :---- |
| LinkedIn | Profile sections (headline, about, experience, education, skills, certifications, featured, recommendations). Post history (last 90 days). Engagement per post (likes, comments, shares). Profile view count. Search appearance count. Connection count. Follower count. | Daily sync |
| Instagram | Bio, profile photo URL, follower count, following count, post count. Feed posts (last 60 days): caption, image URL, likes, comments, saves, reach, impressions. Story views (last 30 days). Reel plays. | 48-hour sync |
| Twitter/X | Bio, follower count, following count. Tweet history (last 60 days): text, impressions, engagements, link clicks, retweets, replies. Profile visits. | 48-hour sync (Phase 2\) |
| YouTube | Channel stats: subscriber count, total views, video count. Per-video: title, description, tags, views, watch time, CTR, average view duration, subscriber change. Upload dates. | Weekly sync |
| PART 2 — ENTERPRISE SOCIAL BRANDING |
| :---: |
Part 2 covers the Social Branding service for companies and organisations. An enterprise account manages its brand presence across social platforms — defining what to post, what not to post, maintaining brand voice consistency, and managing AI-assisted content creation and scheduling across multiple platforms with an internal approval workflow.
| 7\. SERVICE OVERVIEW — ENTERPRISE |
| :---- |
Enterprise Social Branding gives companies a governed, AI-assisted platform to manage their professional brand presence. It is distinct from the individual service in three fundamental ways: it serves an organisation rather than a person, it includes multi-user approval workflows (not just single-user approval), and it includes brand governance rules that define what content is and is not acceptable before the AI generates anything.
| Dimension | Individual Social Branding | Enterprise Social Branding |
| :---- | :---- | :---- |
| Subject | A persons professional brand | A companys brand presence |
| Platforms | Personalised per archetype and persona | Standardised across all company-connected platforms |
| Content strategy | Persona-driven, career-goal aligned | Brand voice and values-driven, audience-targeted |
| Approval workflow | Single user approves | Multi-role workflow: Creator → Editor → Approver |
| Brand governance | Tone rules per persona | Explicit content policy: what to post, what not to post |
| Analytics focus | Individual brand growth, recruiter visibility | Company reach, audience growth, brand sentiment |
| Q-Score integration | Feeds RQx for individual | Not Q-Score integrated — separate enterprise analytics |
## **7.1 Enterprise Account Structure**
* An enterprise account is associated with a company entity (not an individual user)
* Multiple team members can be added to the enterprise account with defined roles
* Three roles: Content Creator (drafts content), Content Editor (reviews and edits), Brand Approver (final approval before posting)
* At least one Brand Approver must be assigned before any content can go live
* Enterprise account connects company social profiles (LinkedIn Company Page, Instagram Business, Twitter/X Business, YouTube Channel)
| 8\. BRAND GOVERNANCE FRAMEWORK — ENTERPRISE |
| :---- |
Brand governance is the defining capability of the Enterprise service. Before the AI generates any content, it operates within a set of brand rules defined by the company. These rules determine what gets created, what gets filtered, and what gets flagged for human review.
## **8.1 Brand Voice Definition**
The enterprise sets its brand voice at account setup. Brand voice is defined across five dimensions:
| Dimension | Options | Example |
| :---- | :---- | :---- |
| Tone | Professional / Conversational / Authoritative / Inspirational / Technical | A fintech company selects: Professional \+ Authoritative |
| Formality | Formal / Semi-formal / Casual | Most enterprises: Semi-formal |
| Perspective | First person (we) / Third person (company name) | Most LinkedIn company posts: First person (we) |
| Language style | Simple and direct / Rich and descriptive / Data-led / Story-led | Tech companies often: Simple and direct \+ Data-led |
| Audience | Talent/Recruitment / Clients/Customers / Industry peers / Investors / General public | Can select multiple; content adapted per audience tag |
## **8.2 Content Policy — What to Post**
* Company milestones: product launches, funding announcements, partnerships, awards
* Thought leadership: industry trends, company perspective on market developments, research and data
* Culture and values: team stories, behind-the-scenes, company events, diversity and inclusion content
* Product and service highlights: feature announcements, case studies, client success stories (with consent)
* Recruitment content: open roles, employer brand, employee testimonials, workplace benefits
* Educational content: how-to guides, industry education, tips relevant to the companys domain
* Engagement content: polls, questions, community challenges aligned to brand values
## **8.3 Content Policy — What Not to Post (Governance Rules)**
The following rule categories are configurable by the enterprise at account setup. The AI applies these rules as filters before generating any content. Content that violates a rule is not queued — it is discarded or flagged for human review.
| Rule Category | Default Setting | Configurable? |
| :---- | :---- | :---- |
| Political statements or partisan content | Blocked — never generated | Yes — enterprise can unlock with justification |
| Commentary on competitors by name | Blocked — never generated | Yes — enterprise can unlock for specific approved comparisons |
| Unverified claims or statistics | Flagged for human review before queuing | No — always flagged |
| Sensitive social topics (religion, race, gender commentary) | Flagged for human review | Yes — enterprise can block entirely |
| Legal or compliance-sensitive content (regulatory, financial) | Flagged for legal review tag | No — always flagged |
| Crisis or incident response content | Blocked from AI generation — must be human-authored | No — always blocked from AI |
| Content featuring named individuals (external) | Requires explicit approval flag | No — always requires approval |
| Off-brand tone (outside defined voice dimensions) | Regenerated automatically before queuing | No — always enforced |
| 9\. ENTERPRISE CONTENT ENGINE |
| :---- |
## **9.1 Content Generation Flow**
| Step | Action | Role Responsible | System Behaviour |
| :---- | :---- | :---- | :---- |
| 1 | Content brief input | Content Creator or AI-initiated | Creator provides topic/theme OR system auto-generates brief from content calendar schedule |
| 2 | Brand governance check | System (automated) | Brief checked against content policy rules. Blocked topics discarded. Flagged topics tagged for review. |
| 3 | AI content generation | System (automated) | AI generates post draft applying: brand voice rules, platform format requirements, 80/20 content model, audience targeting |
| 4 | Creator review | Content Creator | Creator reviews draft, makes edits, adds platform-specific adjustments |
| 5 | Editor review | Content Editor | Editor reviews for brand alignment, tone consistency, factual accuracy |
| 6 | Brand approval | Brand Approver | Final approval. Can approve, request changes, or reject. Only Brand Approver can push to scheduled. |
| 7 | Schedule and post | System (automated) | Approved content scheduled per platform optimal posting time. Posted automatically at scheduled time. |
| 8 | Performance tracking | System (automated) | Impressions, engagement, follower data collected. Brand analytics dashboard updated. |
## **9.2 Enterprise 80/20 Content Model**
The same 80/20 content model applies to enterprise, with enterprise-specific content types:
| Content Type | Category | Description |
| :---- | :---- | :---- |
| Company milestone post | 80% Toolkit | Template: announcement \+ context \+ what it means for customers/team \+ CTA. Fills with company-specific data. |
| Thought leadership post | 80% Toolkit | Template: industry observation \+ company perspective \+ supporting data point \+ question to audience. |
| Culture post | 80% Toolkit | Template: team story or value highlight \+ what it demonstrates about the company \+ employee quote (with consent). |
| Job opening post | 80% Toolkit | Template: role title \+ why this role matters \+ what kind of person thrives here \+ apply link. |
| Educational post | 80% Toolkit | Template: common misconception or question in domain \+ company perspective \+ practical takeaway. |
| Trending topic response | 20% Dynamic | AI monitors industry news. Generates company perspective post when relevant trend detected. Always flagged for Brand Approver review. |
| Milestone reaction | 20% Dynamic | AI auto-generates draft when company milestone event detected (e.g. funding announcement, award won). Requires full approval workflow. |
| Engagement response | 20% Dynamic | AI drafts responses to comments on company posts. Creator reviews before sending. |
| 10\. ACCEPTANCE CRITERIA |
| :---- |
**Part 1 — Individual Social Branding**
| \# | Acceptance Criterion | Pass / Fail |
| :---- | :---- | :---- |
| **1** | OAuth connection completes for all four platforms (LinkedIn, Instagram, Twitter/X, YouTube). Profile data collected on first sync. Sync schedule runs per defined frequency. | \[ \] PASS \[ \] FAIL |
| **2** | Brand Score calculated correctly from all 7 components. Brand Score feeds RQx via defined formula. RQx update event emitted to Assessment and Pathways services on Brand Score change of 5+ points. | \[ \] PASS \[ \] FAIL |
| **3** | Profile analysis runs for all four platforms. Section-by-section audit scores generated. Benchmark against target role applied. Profile recommendations generated with current and recommended text. | \[ \] PASS \[ \] FAIL |
| **4** | Profile recommendations can be approved and applied to the live platform profile. Rejected recommendations discarded. Applied recommendations update the social\_profile\_recommendations table correctly. | \[ \] PASS \[ \] FAIL |
| **5** | Content calendar generated for correct persona with correct platform mix. 80/20 split enforced over any 2-week rolling window. All 6 content calendar rules applied correctly. | \[ \] PASS \[ \] FAIL |
| **6** | Pre-baked toolkit content fills correctly with user-specific data (achievements, Q-Score stats, pathway milestones). All 8 toolkit content types functional. | \[ \] PASS \[ \] FAIL |
| **7** | Dynamic content triggers fire correctly: Q-Score improvement event, pathway milestone event, trending topic detection, profile update trigger. | \[ \] PASS \[ \] FAIL |
| **8** | Approval queue functions correctly: user can approve (with optional edits), reject, or request regeneration for each content item. No content posted without approved status. | \[ \] PASS \[ \] FAIL |
| **9** | Auto-approve mode available as opt-in only. When enabled, content posts without individual approval. Can be disabled at any time. | \[ \] PASS \[ \] FAIL |
| **10** | Approved content posted to correct platform at scheduled time. Platform-specific formatting applied (LinkedIn: no external link in body. Instagram: hashtags appended. YouTube: description and tags generated.) | \[ \] PASS \[ \] FAIL |
| **11** | Engagement queue populated with AI-drafted responses to comments and connection requests. User approval required before sending. | \[ \] PASS \[ \] FAIL |
| **12** | Analytics collected per platform per sync cycle. Performance data stored in social\_content\_performance table. Analytics dashboard displays all tracked metrics with trend lines. | \[ \] PASS \[ \] FAIL |
| **13** | Persona switching updates platform activation recommendations, content calendar strategy, and posting frequency rules immediately. | \[ \] PASS \[ \] FAIL |
| **14** | Archetype-conditional platform activation: Instagram not recommended by default for Technical Specialist or Strategic Leader personas. System surfaces recommendation prompt for relevant personas only. | \[ \] PASS \[ \] FAIL |
**Part 2 — Enterprise Social Branding**
| \# | Acceptance Criterion | Pass / Fail |
| :---- | :---- | :---- |
| **1** | Enterprise account creation completes with brand voice and content policy configuration. Multi-role team setup (Creator, Editor, Approver) functional. Minimum one Approver enforced before content can go live. | \[ \] PASS \[ \] FAIL |
| **2** | Brand governance rules applied before AI content generation. Blocked topics discarded without queuing. Flagged topics tagged and routed to enterprise\_content\_flags table for human review. | \[ \] PASS \[ \] FAIL |
| **3** | All 8 governance rule categories enforced: political content blocked, competitor mentions blocked, unverified claims flagged, sensitive topics flagged, legal content flagged, crisis content blocked from AI, named individuals require approval, off-brand tone regenerated. | \[ \] PASS \[ \] FAIL |
| **4** | Brand voice rules (tone, formality, perspective, language style, audience) applied to all AI-generated content. Off-brand drafts regenerated automatically before entering approval queue. | \[ \] PASS \[ \] FAIL |
| **5** | Three-stage approval workflow enforced: Creator → Editor → Brand Approver. Content cannot skip stages. Only Brand Approver role can push content to scheduled status. | \[ \] PASS \[ \] FAIL |
| **6** | All 8 enterprise content types (5 toolkit \+ 3 dynamic) generated correctly. Trending topic and milestone dynamic content always routed to Brand Approver regardless of workflow stage. | \[ \] PASS \[ \] FAIL |
| **7** | Flagged content resolution workflow completes: flag raised → human reviews → approved/rejected/edited → flag closed. Content entry status updates correctly on resolution. | \[ \] PASS \[ \] FAIL |
| **8** | Enterprise analytics collected per platform. Brand analytics dashboard displays follower growth, impressions, engagement rate, and top-performing posts per platform. | \[ \] PASS \[ \] FAIL |
| **9** | Enterprise content calendar visible across all team member roles with correct status labels per approval stage. Each role sees only the actions available to their role. | \[ \] PASS \[ \] FAIL |

View File

@@ -0,0 +1,275 @@
# Changelogs (main ➜ feature-update)
Date: 26 Mar 2026
Scope: Diff between `origin/main` and `feature-update`
## Summary
`feature-update` is a large feature + architecture update.
- **Scale of change:** 85 files changed, **+11,633 / -3,266** lines.
- **Primary outcomes:**
- Adds **QScore integration** and user-level caching.
- Adds a **Brand Score engine** (with audit output, quick wins, and optional eventing).
- Introduces a more explicit architecture: **Adapters → Use-cases → Repositories → Engine**.
- Improves worker/job processing with **job dispatching + idempotency**.
- Adds **demo/dev ergonomics**: no-auth mode, demo token, and `/demo` UI.
- Adds significant **test coverage** and **documentation**.
---
## Whats new (features added)
### 1) QScore integration
**Goal:** Fetch/compute QScore and persist a read-optimized snapshot for downstream UX and scoring.
**Key additions:**
- API module: `app/api/v1/qscore.py`
- Client: `app/clients/qscore_client.py`
- Service: `app/services/qscore_service.py`
- Schema types: `app/schemas/qscore.py`
- DB cache column via migration:
- `alembic/versions/20260325_000001_add_qscore_summary_to_social_users.py`
- Model update:
- `app/models/user.py` adds `qscore_summary` (JSONB)
**Net effect:** The service can expose QScore data and keep the latest snapshot in the user row for fast reads.
---
### 2) Brand Score engine (+ summaries)
**Goal:** Compute and explain a “Brand Score” with actionable guidance.
**Key additions:**
- Engine modules:
- `app/engine/brand_score_engine.py`
- `app/engine/audit_engine.py`
- `app/engine/persona_engine.py`
- `app/engine/draft_engine.py`
- `app/engine/calendar_engine.py`
- `app/engine/contracts.py`
- `app/engine/scoring_rules.py`
- Eventing:
- `app/services/brand_score_eventing.py`
- DB cache column via migration:
- `alembic/versions/20260325_000002_add_brand_score_summary_to_social_users.py`
- Model update:
- `app/models/user.py` adds `brand_score_summary` (JSONB)
**Behavioral highlights:**
- Brand score output includes structured “**strengths**” and top “**quick wins**” derived from audit explanations.
---
### 3) Job dispatcher + worker pipeline improvements
**Goal:** Make background job handling explicit, testable, and safer on retries.
**Key additions:**
- Job framework:
- `app/jobs/dispatcher.py` (routes `job_type` → handler)
- `app/jobs/definitions.py`
- `app/jobs/__init__.py`
**Notable behaviors:**
- Optional **idempotency key** support (Redis `SETEX`, 24h TTL) to avoid double-processing when messages are re-delivered.
---
### 4) Demo/dev UX improvements
**Goal:** Run and validate the service without external auth dependencies in dev/demo scenarios.
**Key additions:**
- `app/auth/dependencies.py`
- `no_auth_mode` (always treat caller as `demo_user_id`)
- `demo_auth_enabled` + token value `demo` shortcut
- `app/main.py`
- `GET /demo` serves `app/static/demo.html` (fallback redirects to `/docs`)
- `app/static/demo.html` (mini UI)
---
## What changed (behavioral refactors)
### APIs: “fat routes” ➜ use-case driven routes
Many endpoints were refactored to:
- Stop doing SQLAlchemy querying/ownership checks directly inside routers.
- Delegate to use-cases via `provide_use_case(...)`.
**Examples of refactored routers:**
- `app/api/v1/profiles.py`
- `app/api/v1/content.py`
- `app/api/v1/internal.py`
- Dashboard state endpoint in `app/main.py` now delegates to `app/use_cases/get_dashboard.py`
**Net effect:** Controllers become thinner and easier to reason about; business and persistence logic becomes reusable and testable.
---
### Scoring logic: service module ➜ pure engine module
- Previous: `app/services/scoring_service.py` contained large amounts of pure scoring logic.
- Now: `app/services/scoring_service.py` is a **compatibility wrapper** that re-exports scoring functions/constants from `app/engine/scoring_rules.py`.
**Why:** Centralizes domain logic in the Engine layer and keeps import stability for older code.
---
## What was removed (or relocated)
### 1) `app/services/branding_intelligence.py` removed
- Deleted: `app/services/branding_intelligence.py`
- Replaced by layered structure:
- Added: `app/adapters/branding_intelligence.py`
This is part of a broader “**services → adapters**” refactor.
### 2) Service modules moved under adapters
Renames (logical move; functionality preserved):
- `app/services/ai_service.py``app/adapters/ai_service.py`
- `app/services/brightdata_service.py``app/adapters/brightdata_service.py`
- `app/services/scrapetable_service.py``app/adapters/scrapetable_service.py`
---
## Architecture: before vs after
### Previous architecture (main)
**Common traits observed in the diff:**
- Routers frequently performed:
- DB access (`select`, `update`, joins)
- Ownership/security checks
- Data merging/enrichment logic
- Commit/flush patterns
- Most domain logic lived in *service* modules, often mixing:
- domain rules
- provider orchestration
- persistence decisions
**Typical pain points:**
- Harder to test logic without DB + IO.
- Harder to reuse workflows between:
- HTTP routes
- background jobs
- agent/worker flows
- High coupling between external providers and business logic.
---
### Current architecture (feature-update)
The code is reorganized around clearer boundaries:
1) **Adapters** (`app/adapters/`)
- External IO: AI providers, BrightData, Scrapetable, branding intelligence provider glue.
2) **Use-cases** (`app/use_cases/`)
- Application workflows (orchestration):
- validate inputs
- call repos, engines, adapters
- decide persistence / commit points
3) **Repositories** (`app/repositories/`)
- Database access patterns:
- fetch by clerk id
- fetch profile for user
- save scores/drafts
4) **Engine** (`app/engine/`)
- Pure or mostly-pure domain logic:
- scoring rules
- auditing
- persona generation
- calendar/draft logic
5) **API controllers** (`app/api/...`)
- Translate HTTP requests to use-case calls.
- Convert errors to HTTP codes.
---
## Why the new architecture is better
### 1) Testability
- Engine logic can be unit-tested without network or DB.
- Use-cases can be tested with mocked adapters and in-memory db sessions.
### 2) Separation of concerns (less coupling)
- External providers are isolated in adapters.
- Domain logic is isolated in engine modules.
- DB access is consolidated and reusable in repositories.
### 3) Reuse across execution contexts
The same use-cases can be invoked from:
- REST APIs
- workers/jobs
- agent flows
This reduces duplication and “slightly-different” implementations.
### 4) Safer background jobs
- Dispatcher introduces structured routing and idempotency support.
- Makes retries less risky and easier to reason about.
### 5) Better dev ergonomics
- No-auth mode and a demo UI make local validation faster.
- Less dependency on Clerk for basic smoke tests.
---
## Developer-facing changes to be aware of
### Authentication behavior
- `app/auth/dependencies.py` now supports:
- **global no-auth mode** (treat all calls as `demo_user_id`)
- **demo token** shortcut (token == `demo`)
### DB migrations now required
- Brand/QScore summaries require running Alembic migrations before using those features.
### Import path changes
- External integrations moved under `app/adapters/*`.
- Scoring logic moved to `app/engine/scoring_rules.py` (service remains as a compatibility re-export).
---
## Tests added/updated
**New tests:**
- `tests/test_engine.py`
- `tests/test_hardening.py`
- `tests/test_qscore_integration.py`
- `tests/test_rqx_formula.py`
- `tests/test_worker_convergence.py`
**Updated tests:**
- `tests/test_branding_intelligence.py`
---
## Documentation added
A significant set of planning/architecture docs was added, including:
- `docs/PRD.md`
- `docs/qscore-integration.md`
- `docs/eventing-contract.md`
- plus multiple architecture/plan/audit checklists under `docs/`
---
## Quick file index (most important additions)
- Engine: `app/engine/*`
- Use-cases: `app/use_cases/*`
- Repositories: `app/repositories/*`
- QScore: `app/api/v1/qscore.py`, `app/services/qscore_service.py`, `app/clients/qscore_client.py`, `app/schemas/qscore.py`
- DB migrations: `alembic/versions/20260325_000001_*`, `alembic/versions/20260325_000002_*`
- Demo: `app/static/demo.html`, `GET /demo` in `app/main.py`
- Jobs: `app/jobs/dispatcher.py`

396
social_branding/PRD.md Normal file
View File

@@ -0,0 +1,396 @@
**GrowQR**
**SOCIAL BRANDING**
**DEVELOPER BRD — TECHNICAL SPECIFICATION**
Individual Social Branding • Enterprise Social Branding • 4 Platforms • 6 Personas • v1.0 • March 2026
| Social Branding Microservices This document contains specifications, business logic, and acceptance criteria for development. |
| :---: |
| Document Title | Social Branding Service — Developer BRD Technical Specification |
| :---- | :---- |
| Version | 1.0 — March 2026 |
| :---- | :---- |
| Service Type | Standalone Microservice — Part of Opportunity Module |
| :---- | :---- |
| Target Platforms | LinkedIn | Instagram | Twitter/X | YouTube |
| :---- | :---- |
| Target Launch | April 1st — LinkedIn, Instagram, YouTube, Twitter/X , Git |
| :---- | :---- |
| Part 1 | Individual Social Branding — 6 end-goal personas, full automation with approval |
| :---- | :---- |
| Part 2 | Enterprise Social Branding — Company brand presence, governance, multi-platform management |
| :---- | :---- |
| Q-Score Integration | Brand Score (0100) feeds RQx. Q-Score changes trigger automatic profile and content updates. |
| :---- | :---- |
| Data Collection | Method TBD by technical team — BRD specifies data requirements only |
| :---- | :---- |
| PART 1 — INDIVIDUAL SOCIAL BRANDING |
| :---: |
Part 1 covers the Social Branding service for individual GrowQR users. It is a fully automated, AI-managed presence builder across LinkedIn, Instagram, Twitter/X, and YouTube — with user approval at every execution step.
| 1\. SERVICE OVERVIEW — INDIVIDUAL |
| :---- |
The Individual Social Branding service transforms a users professional presence from a passive profile into an active, consistent, and strategically managed brand. The service operates on a Scrape → Analyse → Generate → Approve → Post → Track loop, fully managed by GrowQRs AI layer.
The service is built on five structural pillars drawn from proven social branding principles:
| Pillar | Definition | How GrowQR Implements It |
| :---- | :---- | :---- |
| Consistency | Uniform brand voice, visual style, and messaging across all platforms | AI enforces tone, vocabulary, and visual style rules per persona across all connected platforms |
| Target Audience | Understanding the social habits of the users ideal audience (recruiters, clients, peers, investors) | Audience profile built from users pathway archetype, target role, and Q-Score profile |
| Content Strategy | A defined mix of educational, entertaining, and inspirational content mapped to brand values | 80/20 content model: 80% pre-baked persona toolkit, 20% dynamic AI-generated content |
| Engagement | Active interaction with followers: likes, comments, DMs, connection requests | AI drafts engagement responses; user approves or auto-approves based on engagement rules |
| Platform Selection | Right platforms for the users archetype and target audience | Archetype-conditional platform activation — not all platforms recommended to all users |
## **1.1 The Automation Loop**
| Stage | Action | Human Touch Point |
| :---- | :---- | :---- |
| 1\. Connect | User connects social accounts via OAuth | One-time setup per platform |
| 2\. Scrape / Collect | System collects profile data, post history, engagement metrics, follower data | None — automated |
| 3\. Analyse | AI analyses profile completeness, content performance, audience alignment, Brand Score calculated | User reviews Brand Score dashboard |
| 4\. Generate | AI generates: profile rewrites, content calendar, post drafts, engagement responses | User reviews all generated content |
| 5\. Approve | User approves, edits, or rejects each item in the approval queue | Primary user interaction point |
| 6\. Post / Execute | Approved content scheduled and posted. Profile updates applied. Engagement responses sent. | None — automated post-approval |
| 7\. Track | System monitors: impressions, profile views, follower growth, engagement rate, recruiter search appearances | User reviews weekly analytics dashboard |
| 8\. Feed Back | Performance data feeds Brand Score and RQx Q-Score. Pathway engine updates recommendations. | None — automated |
| 2\. BRAND SCORE — THE SOCIAL Q-SCORE |
| :---- |
Brand Score is a single 0100 metric that measures the strength, consistency, and discoverability of a users professional presence across all connected platforms. It is GrowQRs proprietary social presence measurement and feeds directly into RQx (Reputation Quotient) in the Q-Score engine.
| Brand Score is not a vanity metric. It is calculated from objective, measurable signals. As the user takes actions recommended by the Social Branding service, their Brand Score improves. Brand Score improvement directly improves their RQx Q-Score, which in turn updates their pathway recommendations. |
| :---- |
## **2.1 Brand Score Components**
| Component | Weight | What It Measures |
| :---- | :---- | :---- |
| Profile Completeness | 20% | All profile sections populated, keyword-optimised, and aligned to target role across active platforms |
| Content Consistency | 20% | Posting frequency maintained, tone consistent, visual style uniform across platforms |
| Audience Growth | 15% | Follower/connection growth rate over 30-day rolling window |
| Engagement Rate | 15% | Likes, comments, shares, and saves as a percentage of reach per post |
| Recruiter Visibility | 15% | Profile appearance rate in relevant recruiter and talent searches (LinkedIn primary) |
| Content Quality | 10% | AI-assessed relevance, originality, and alignment to persona content framework |
| Cross-Platform Consistency | 5% | Messaging and voice alignment across all connected platforms |
## **2.2 Brand Score → RQx Integration**
* Brand Score calculated after every platform data sync (example: frequency: daily for LinkedIn, 48hrs for others)
* Brand Score mapped to RQx using a defined conversion formula: RQx contribution \= Brand Score × 0.4 (40% weighting of RQx from Brand Score)
* RQx update event emitted to Assessment Service and Pathways Service on every Brand Score change of 5+ points
* Pathways engine re-evaluates Social Branding touchpoint recommendations on RQx update
* Users Brand Score history stored and displayed as a trend line on the Social Branding dashboard
| 3\. SIX END-GOAL PERSONAS — CONTENT FRAMEWORK |
| :---- |
Every users Social Branding strategy is driven by their end-goal persona. The persona is derived from the users active pathway archetype, target role, and career goal input. Users can switch personas as their goals evolve. Each persona has a defined platform mix, content angle, and posting frequency.
| Platform activation is archetype-conditional. Not all platforms are recommended to all users. The system activates platforms relevant to the users persona and prompts the user to connect them. Users can override and connect any platform manually. |
| :---- |
| PERSONA 1: JOB SEEKER Archetype: All archetypes — active job search phase |
| :---- |
| **Recommended Platforms** LinkedIn (primary), Twitter/X (secondary for tech/creative roles) **Content Angle** Recruiter visibility, skills signalling, open-to-work positioning, achievement highlights **Posting Frequency** LinkedIn: 4x per week. Twitter/X: 3x per week if active. |
| PERSONA 2: CAREER TRANSITIONER Archetype: All archetypes — changing domain or role type |
| :---- |
| **Recommended Platforms** LinkedIn (primary), Instagram (if transitioning to creative/coaching/consulting) **Content Angle** Narrative reframing: connecting past experience to new direction, learning journey documentation **Posting Frequency** LinkedIn: 3x per week. Instagram: 2x per week if active. |
| PERSONA 3: THOUGHT LEADER Archetype: Strategic Leader, Entrepreneurial Builder, Domain Expert |
| :---- |
| **Recommended Platforms** LinkedIn (primary), Twitter/X (primary), YouTube (secondary) **Content Angle** Industry insights, opinion pieces, trend analysis, frameworks and models, contrarian takes **Posting Frequency** LinkedIn: 5x per week. Twitter/X: daily. YouTube: 1x per month minimum. |
| PERSONA 4: DOMAIN EXPERT Archetype: Technical Specialist, Creative Innovator |
| :---- |
| **Recommended Platforms** LinkedIn (primary), GitHub (external link), YouTube (tutorials/walkthroughs) **Content Angle** Deep technical content, how-to posts, case studies, project showcases, certification highlights **Posting Frequency** LinkedIn: 3x per week. YouTube: 2x per month. |
| PERSONA 5: ENTREPRENEUR / FOUNDER Archetype: Entrepreneurial Builder |
| :---- |
| **Recommended Platforms** LinkedIn (primary), Twitter/X (primary), Instagram (brand building), YouTube (storytelling) **Content Angle** Build-in-public content, startup journey, lessons learned, team culture, product milestones **Posting Frequency** LinkedIn: 5x per week. Twitter/X: daily. Instagram: 3x per week. YouTube: 2x per month. |
| PERSONA 6: EXECUTIVE / ENTERPRISE LEADER Archetype: Strategic Leader — VP, Director, C-suite level |
| :---- |
| **Recommended Platforms** LinkedIn (primary), Twitter/X (secondary) **Content Angle** Executive presence: strategic vision, culture and values, industry leadership, org transformation, speaking engagements **Posting Frequency** LinkedIn: 3x per week. Twitter/X: 2x per week. |
| 4\. THE 80/20 CONTENT MODEL |
| :---- |
All content generated by GrowQRs Social Branding service follows an 80/20 split: 80% pre-baked toolkit content and 20% dynamic AI-generated content. This balance ensures consistency and quality (80%) while maintaining relevance and freshness (20%).
## **4.1 80% — Pre-Baked Toolkit**
The pre-baked toolkit is a library of proven content frameworks, post templates, hooks, and evergreen structures mapped to each persona and platform. This content is designed, tested, and maintained by GrowQR. It does not require AI generation — it is filled with user-specific data at execution time.
| Content Type | Description | Persona Applicability |
| :---- | :---- | :---- |
| Achievement Post | Structured template: milestone \+ what it took \+ what you learned. Fills with users real achievements from pathway completions. | All personas |
| Skills Signal Post | Highlights a specific skill or certification. Links to Q-Score improvement data. | Job Seeker, Domain Expert, Career Transitioner |
| Insight Share | Short opinion or observation on an industry trend. Structure: Hook \+ Insight \+ Question to audience. | Thought Leader, Executive, Entrepreneur |
| Career Story Post | Narrative format: where I was \+ what changed \+ where I am now. Used for transitions and milestones. | Career Transitioner, Entrepreneur |
| Project Showcase | Work sample or project result with context. Visual-first for Instagram; text+image for LinkedIn. | Domain Expert, Creative Innovator, Entrepreneur |
| Engagement Prompt | Question or poll to drive comments. Mapped to users domain for relevant audience response. | All personas |
| Weekly Reflection | End-of-week summary: what I worked on, what I learned, whats next. | Thought Leader, Entrepreneur, Executive |
| Company/Role Spotlight | Highlights a company or role the user is targeting or has experience with. Builds recruiter relevance. | Job Seeker, Career Transitioner |
## **4.2 20% — Dynamic Content**
Dynamic content is AI-generated in real-time based on signals from the users platform activity, Q-Score progress, pathway milestones, and trending topics in their domain. This content is fresh, timely, and personalised — it cannot be pre-baked.
* Q-Score improvement post: auto-generated when user improves a Q-Score by 10+ points. Frames the improvement as a professional growth story.
* Pathway milestone post: auto-generated when user completes a course, earns a certificate, or achieves a pathway milestone.
* Trending topic response: AI monitors trending topics in the users domain. Generates a short opinion post when a relevant trend is detected.
* Interview or job application event: auto-generated encouragement and visibility post when user applies for a role or secures an interview (with user consent).
* Engagement response drafts: AI drafts replies to comments on the users posts, maintaining persona tone and voice.
* Profile update trigger: when users Q-Scores or pathway status changes significantly, AI generates updated headline, about section, and skills list for user approval.
## **4.3 Content Calendar Generation Rules**
| Rule | Description |
| :---- | :---- |
| Rule 1: Frequency Enforcement | System enforces minimum posting frequency per persona. If user has not approved content for upcoming slots, system sends reminder 48hrs in advance. |
| Rule 2: Platform Sequencing | Content is not duplicated across platforms. Each platform receives a uniquely formatted version adapted to that platforms style and audience. |
| Rule 3: Content Mix Enforcement | System ensures the 80/20 split is maintained over any 2-week rolling window. Prevents over-reliance on either toolkit or dynamic content. |
| Rule 4: No Auto-Post Without Approval | No content is ever posted without explicit user approval. Auto-approve mode is available as an opt-in setting only. |
| Rule 5: Tone Lock | Once users brand voice is established (after first 2 weeks), tone settings are locked unless user explicitly resets them. |
| Rule 6: Sensitive Topic Filter | AI applies a topic filter before generating content. Posts that touch on politically sensitive, legally risky, or reputationally harmful territory are flagged and not queued for approval. |
| 5\. PLATFORM SPECIFICATIONS — INDIVIDUAL |
| :---- |
## **5.1 LinkedIn**
| Capability | Specification |
| :---- | :---- |
| Profile Analysis | Audit: Headline, About, Experience, Skills, Recommendations, Featured section, Activity. Score each section 0100. Benchmark against target role requirements and top 10% of professionals in same role. |
| Profile Rewrite | AI generates optimised versions of: Headline (3 variants), About section, Experience bullet points (per role), Skills list (mapped to Q-Scores and target JD keywords). User selects and approves. |
| Recruiter Visibility | Keyword gap analysis: identifies terms recruiters search for this role that are missing from profile. Injects keywords into profile sections naturally. |
| Content Posting | Supports: text posts, image posts, document carousels, polls, article links. Content formatted to LinkedIn algorithm best practices (hook in first 2 lines, no external links in body). |
| Connection Strategy | Identifies target connections based on users pathway: target companies, role peers, hiring managers in target domain. AI drafts personalised connection request notes. |
| Engagement Automation | AI drafts comments on posts from target connections and industry leaders. User approves before sending. Builds visibility with relevant audience. |
| Analytics Tracked | Profile views (7-day, 30-day), Search appearances, Post impressions, Engagement rate per post, Connection acceptance rate, Follower growth |
## **5.2 Instagram**
| Instagram is activated for: Career Transitioner (creative/coaching roles), Entrepreneur/Founder, Domain Expert (creative/design roles). Not recommended by default for Technical Specialist or Strategic Leader personas unless user opts in. |
| :---- |
| Capability | Specification |
| :---- | :---- |
| Profile Analysis | Bio, profile photo, link-in-bio, highlight covers, grid aesthetic consistency, story frequency. Score for professional brand alignment. |
| Content Types | Feed posts (static image, carousel), Reels (short-form video), Stories (ephemeral). Each type has distinct content templates in the pre-baked toolkit. |
| Visual Style Consistency | AI enforces visual brand rules: colour palette (derived from users LinkedIn brand colours), font style, filter consistency. Applied to all generated visual templates. |
| Caption Framework | Each caption follows: Hook (first line visible before more) \+ Value (body) \+ CTA (final line) \+ Hashtags (max 5, domain-specific). Hashtag bank maintained per persona. |
| Story Strategy | Stories used for: behind-the-scenes content, quick tips, polls, Q\&As. Frequency: 35 stories per week. Story templates provided per persona. |
| Analytics Tracked | Reach, Impressions, Profile visits, Follower growth, Story views, Reel plays, Link-in-bio clicks, Saves per post |
## **5.3 Twitter / X**
| Twitter/X is targeted for Phase 2 launch. Architecture and data model specified here for development readiness. April 1st launch excludes Twitter/X. |
| :---- |
| Capability | Specification |
| :---- | :---- |
| Profile Analysis | Bio (160 chars), header image, pinned tweet, posting frequency, engagement rate, follower-to-following ratio. |
| Content Types | Short posts (under 280 chars), Threads (multi-tweet narrative), Quote posts (with commentary), Replies (engagement strategy). |
| Thread Framework | Threads used for: insight breakdowns, how-to guides, career lessons, domain deep-dives. Format: Hook tweet \+ 510 body tweets \+ CTA final tweet. |
| Posting Strategy | Optimal posting times calculated per users audience timezone. Threads on weekdays, shorter posts and replies on weekends. |
| Analytics Tracked | Impressions, Engagements, Profile clicks, Link clicks, Follower growth, Thread completion rate |
## **5.4 YouTube**
| Capability | Specification |
| :---- | :---- |
| Channel Analysis | Channel art, About section, playlist structure, video titles and descriptions (SEO), thumbnail consistency, upload frequency, subscriber growth rate. |
| Content Types | Long-form (1020 min): deep dives, case studies, tutorials. Short-form (YouTube Shorts, under 60 sec): tips, quick insights, career advice clips. |
| Video Brief Generation | AI generates video briefs: title (3 variants), hook script (first 30 seconds), chapter outline, description with keywords, tags, thumbnail concept. User records; AI does not generate video. |
| SEO Optimisation | Title keyword analysis, description keyword injection, tag strategy, chapter timestamps. Benchmarked against top-performing videos in users domain. |
| Thumbnail Strategy | AI generates thumbnail design brief: text overlay, colour scheme, facial expression guidance (if talking head). Thumbnail template provided per persona. |
| Upload Frequency | Persona-based targets: Thought Leader (1x/month minimum), Domain Expert (2x/month), Entrepreneur (2x/month). System prompts user when cadence is falling behind. |
| Analytics Tracked | Views, Watch time, Subscriber growth, Click-through rate (thumbnails), Average view duration, Top traffic sources |
| 6\. DATA REQUIREMENTS — INDIVIDUAL |
| :---- |
| Data collection method (API vs scraping vs user-authenticated export) is TBD and left to the technical team. This section specifies what data is required. The technical team must define the collection mechanism, document any legal or rate-limit constraints, and confirm data availability before development of the collection layer. |
| :---- |
| Platform | Data Required | Frequency |
| :---- | :---- | :---- |
| LinkedIn | Profile sections (headline, about, experience, education, skills, certifications, featured, recommendations). Post history (last 90 days). Engagement per post (likes, comments, shares). Profile view count. Search appearance count. Connection count. Follower count. | Daily sync |
| Instagram | Bio, profile photo URL, follower count, following count, post count. Feed posts (last 60 days): caption, image URL, likes, comments, saves, reach, impressions. Story views (last 30 days). Reel plays. | 48-hour sync |
| Twitter/X | Bio, follower count, following count. Tweet history (last 60 days): text, impressions, engagements, link clicks, retweets, replies. Profile visits. | 48-hour sync (Phase 2\) |
| YouTube | Channel stats: subscriber count, total views, video count. Per-video: title, description, tags, views, watch time, CTR, average view duration, subscriber change. Upload dates. | Weekly sync |
| PART 2 — ENTERPRISE SOCIAL BRANDING |
| :---: |
Part 2 covers the Social Branding service for companies and organisations. An enterprise account manages its brand presence across social platforms — defining what to post, what not to post, maintaining brand voice consistency, and managing AI-assisted content creation and scheduling across multiple platforms with an internal approval workflow.
| 7\. SERVICE OVERVIEW — ENTERPRISE |
| :---- |
Enterprise Social Branding gives companies a governed, AI-assisted platform to manage their professional brand presence. It is distinct from the individual service in three fundamental ways: it serves an organisation rather than a person, it includes multi-user approval workflows (not just single-user approval), and it includes brand governance rules that define what content is and is not acceptable before the AI generates anything.
| Dimension | Individual Social Branding | Enterprise Social Branding |
| :---- | :---- | :---- |
| Subject | A persons professional brand | A companys brand presence |
| Platforms | Personalised per archetype and persona | Standardised across all company-connected platforms |
| Content strategy | Persona-driven, career-goal aligned | Brand voice and values-driven, audience-targeted |
| Approval workflow | Single user approves | Multi-role workflow: Creator → Editor → Approver |
| Brand governance | Tone rules per persona | Explicit content policy: what to post, what not to post |
| Analytics focus | Individual brand growth, recruiter visibility | Company reach, audience growth, brand sentiment |
| Q-Score integration | Feeds RQx for individual | Not Q-Score integrated — separate enterprise analytics |
## **7.1 Enterprise Account Structure**
* An enterprise account is associated with a company entity (not an individual user)
* Multiple team members can be added to the enterprise account with defined roles
* Three roles: Content Creator (drafts content), Content Editor (reviews and edits), Brand Approver (final approval before posting)
* At least one Brand Approver must be assigned before any content can go live
* Enterprise account connects company social profiles (LinkedIn Company Page, Instagram Business, Twitter/X Business, YouTube Channel)
| 8\. BRAND GOVERNANCE FRAMEWORK — ENTERPRISE |
| :---- |
Brand governance is the defining capability of the Enterprise service. Before the AI generates any content, it operates within a set of brand rules defined by the company. These rules determine what gets created, what gets filtered, and what gets flagged for human review.
## **8.1 Brand Voice Definition**
The enterprise sets its brand voice at account setup. Brand voice is defined across five dimensions:
| Dimension | Options | Example |
| :---- | :---- | :---- |
| Tone | Professional / Conversational / Authoritative / Inspirational / Technical | A fintech company selects: Professional \+ Authoritative |
| Formality | Formal / Semi-formal / Casual | Most enterprises: Semi-formal |
| Perspective | First person (we) / Third person (company name) | Most LinkedIn company posts: First person (we) |
| Language style | Simple and direct / Rich and descriptive / Data-led / Story-led | Tech companies often: Simple and direct \+ Data-led |
| Audience | Talent/Recruitment / Clients/Customers / Industry peers / Investors / General public | Can select multiple; content adapted per audience tag |
## **8.2 Content Policy — What to Post**
* Company milestones: product launches, funding announcements, partnerships, awards
* Thought leadership: industry trends, company perspective on market developments, research and data
* Culture and values: team stories, behind-the-scenes, company events, diversity and inclusion content
* Product and service highlights: feature announcements, case studies, client success stories (with consent)
* Recruitment content: open roles, employer brand, employee testimonials, workplace benefits
* Educational content: how-to guides, industry education, tips relevant to the companys domain
* Engagement content: polls, questions, community challenges aligned to brand values
## **8.3 Content Policy — What Not to Post (Governance Rules)**
The following rule categories are configurable by the enterprise at account setup. The AI applies these rules as filters before generating any content. Content that violates a rule is not queued — it is discarded or flagged for human review.
| Rule Category | Default Setting | Configurable? |
| :---- | :---- | :---- |
| Political statements or partisan content | Blocked — never generated | Yes — enterprise can unlock with justification |
| Commentary on competitors by name | Blocked — never generated | Yes — enterprise can unlock for specific approved comparisons |
| Unverified claims or statistics | Flagged for human review before queuing | No — always flagged |
| Sensitive social topics (religion, race, gender commentary) | Flagged for human review | Yes — enterprise can block entirely |
| Legal or compliance-sensitive content (regulatory, financial) | Flagged for legal review tag | No — always flagged |
| Crisis or incident response content | Blocked from AI generation — must be human-authored | No — always blocked from AI |
| Content featuring named individuals (external) | Requires explicit approval flag | No — always requires approval |
| Off-brand tone (outside defined voice dimensions) | Regenerated automatically before queuing | No — always enforced |
| 9\. ENTERPRISE CONTENT ENGINE |
| :---- |
## **9.1 Content Generation Flow**
| Step | Action | Role Responsible | System Behaviour |
| :---- | :---- | :---- | :---- |
| 1 | Content brief input | Content Creator or AI-initiated | Creator provides topic/theme OR system auto-generates brief from content calendar schedule |
| 2 | Brand governance check | System (automated) | Brief checked against content policy rules. Blocked topics discarded. Flagged topics tagged for review. |
| 3 | AI content generation | System (automated) | AI generates post draft applying: brand voice rules, platform format requirements, 80/20 content model, audience targeting |
| 4 | Creator review | Content Creator | Creator reviews draft, makes edits, adds platform-specific adjustments |
| 5 | Editor review | Content Editor | Editor reviews for brand alignment, tone consistency, factual accuracy |
| 6 | Brand approval | Brand Approver | Final approval. Can approve, request changes, or reject. Only Brand Approver can push to scheduled. |
| 7 | Schedule and post | System (automated) | Approved content scheduled per platform optimal posting time. Posted automatically at scheduled time. |
| 8 | Performance tracking | System (automated) | Impressions, engagement, follower data collected. Brand analytics dashboard updated. |
## **9.2 Enterprise 80/20 Content Model**
The same 80/20 content model applies to enterprise, with enterprise-specific content types:
| Content Type | Category | Description |
| :---- | :---- | :---- |
| Company milestone post | 80% Toolkit | Template: announcement \+ context \+ what it means for customers/team \+ CTA. Fills with company-specific data. |
| Thought leadership post | 80% Toolkit | Template: industry observation \+ company perspective \+ supporting data point \+ question to audience. |
| Culture post | 80% Toolkit | Template: team story or value highlight \+ what it demonstrates about the company \+ employee quote (with consent). |
| Job opening post | 80% Toolkit | Template: role title \+ why this role matters \+ what kind of person thrives here \+ apply link. |
| Educational post | 80% Toolkit | Template: common misconception or question in domain \+ company perspective \+ practical takeaway. |
| Trending topic response | 20% Dynamic | AI monitors industry news. Generates company perspective post when relevant trend detected. Always flagged for Brand Approver review. |
| Milestone reaction | 20% Dynamic | AI auto-generates draft when company milestone event detected (e.g. funding announcement, award won). Requires full approval workflow. |
| Engagement response | 20% Dynamic | AI drafts responses to comments on company posts. Creator reviews before sending. |
| 10\. ACCEPTANCE CRITERIA |
| :---- |
**Part 1 — Individual Social Branding**
| \# | Acceptance Criterion | Pass / Fail |
| :---- | :---- | :---- |
| **1** | OAuth connection completes for all four platforms (LinkedIn, Instagram, Twitter/X, YouTube). Profile data collected on first sync. Sync schedule runs per defined frequency. | \[ \] PASS \[ \] FAIL |
| **2** | Brand Score calculated correctly from all 7 components. Brand Score feeds RQx via defined formula. RQx update event emitted to Assessment and Pathways services on Brand Score change of 5+ points. | \[ \] PASS \[ \] FAIL |
| **3** | Profile analysis runs for all four platforms. Section-by-section audit scores generated. Benchmark against target role applied. Profile recommendations generated with current and recommended text. | \[ \] PASS \[ \] FAIL |
| **4** | Profile recommendations can be approved and applied to the live platform profile. Rejected recommendations discarded. Applied recommendations update the social\_profile\_recommendations table correctly. | \[ \] PASS \[ \] FAIL |
| **5** | Content calendar generated for correct persona with correct platform mix. 80/20 split enforced over any 2-week rolling window. All 6 content calendar rules applied correctly. | \[ \] PASS \[ \] FAIL |
| **6** | Pre-baked toolkit content fills correctly with user-specific data (achievements, Q-Score stats, pathway milestones). All 8 toolkit content types functional. | \[ \] PASS \[ \] FAIL |
| **7** | Dynamic content triggers fire correctly: Q-Score improvement event, pathway milestone event, trending topic detection, profile update trigger. | \[ \] PASS \[ \] FAIL |
| **8** | Approval queue functions correctly: user can approve (with optional edits), reject, or request regeneration for each content item. No content posted without approved status. | \[ \] PASS \[ \] FAIL |
| **9** | Auto-approve mode available as opt-in only. When enabled, content posts without individual approval. Can be disabled at any time. | \[ \] PASS \[ \] FAIL |
| **10** | Approved content posted to correct platform at scheduled time. Platform-specific formatting applied (LinkedIn: no external link in body. Instagram: hashtags appended. YouTube: description and tags generated.) | \[ \] PASS \[ \] FAIL |
| **11** | Engagement queue populated with AI-drafted responses to comments and connection requests. User approval required before sending. | \[ \] PASS \[ \] FAIL |
| **12** | Analytics collected per platform per sync cycle. Performance data stored in social\_content\_performance table. Analytics dashboard displays all tracked metrics with trend lines. | \[ \] PASS \[ \] FAIL |
| **13** | Persona switching updates platform activation recommendations, content calendar strategy, and posting frequency rules immediately. | \[ \] PASS \[ \] FAIL |
| **14** | Archetype-conditional platform activation: Instagram not recommended by default for Technical Specialist or Strategic Leader personas. System surfaces recommendation prompt for relevant personas only. | \[ \] PASS \[ \] FAIL |
**Part 2 — Enterprise Social Branding**
| \# | Acceptance Criterion | Pass / Fail |
| :---- | :---- | :---- |
| **1** | Enterprise account creation completes with brand voice and content policy configuration. Multi-role team setup (Creator, Editor, Approver) functional. Minimum one Approver enforced before content can go live. | \[ \] PASS \[ \] FAIL |
| **2** | Brand governance rules applied before AI content generation. Blocked topics discarded without queuing. Flagged topics tagged and routed to enterprise\_content\_flags table for human review. | \[ \] PASS \[ \] FAIL |
| **3** | All 8 governance rule categories enforced: political content blocked, competitor mentions blocked, unverified claims flagged, sensitive topics flagged, legal content flagged, crisis content blocked from AI, named individuals require approval, off-brand tone regenerated. | \[ \] PASS \[ \] FAIL |
| **4** | Brand voice rules (tone, formality, perspective, language style, audience) applied to all AI-generated content. Off-brand drafts regenerated automatically before entering approval queue. | \[ \] PASS \[ \] FAIL |
| **5** | Three-stage approval workflow enforced: Creator → Editor → Brand Approver. Content cannot skip stages. Only Brand Approver role can push content to scheduled status. | \[ \] PASS \[ \] FAIL |
| **6** | All 8 enterprise content types (5 toolkit \+ 3 dynamic) generated correctly. Trending topic and milestone dynamic content always routed to Brand Approver regardless of workflow stage. | \[ \] PASS \[ \] FAIL |
| **7** | Flagged content resolution workflow completes: flag raised → human reviews → approved/rejected/edited → flag closed. Content entry status updates correctly on resolution. | \[ \] PASS \[ \] FAIL |
| **8** | Enterprise analytics collected per platform. Brand analytics dashboard displays follower growth, impressions, engagement rate, and top-performing posts per platform. | \[ \] PASS \[ \] FAIL |
| **9** | Enterprise content calendar visible across all team member roles with correct status labels per approval stage. Each role sees only the actions available to their role. | \[ \] PASS \[ \] FAIL |

View File

@@ -0,0 +1,458 @@
# Social Branding Service Audit — Architecture, Integration, Plan/PRD Alignment
Date: 2026-03-25
## Purpose
This report updates the prior audit (`docs/plan-prd-implementation-audit.md`, dated 2026-03-23) with:
- a detailed review of **layering leaks / integration issues** (surface vs service vs engine)
- a clear summary of **how far weve progressed since the prior audit**
- a mapping of the current implementation against:
- the **narrow plan** in `docs/plan.md`
- the broader **PRD** in `docs/PRD.md`
- an explicit **acceptance criteria coverage** summary (met vs not met)
Auth is treated as non-blocking unless it materially affects architecture boundaries.
---
## Executive Summary
The architecture is **significantly more aligned** to the desired Engine → Service (Use-cases) → Surface split than it was in the 2026-03-23 audit.
Key improvements versus the prior audit:
- an explicit `app/engine/` package now exists with normalized I/O contracts (`app/engine/contracts.py`)
- API routes mostly delegate to `app/use_cases/*` orchestration modules
- persistence is generally accessed via `app/repositories/*`
- Redis worker has a functional job execution path (`job_type`) and idempotency semantics
- migrations are now the schema source of truth (no startup `create_all()` behavior)
However, there are still **layering leaks** and clarity issues:
- the engine layer depends on `app/services/scoring_service.py` (a layer inversion)
- `app/services/` mixes concerns (domain logic + adapters + AI provider orchestration)
- surfaces still pass DB sessions directly into use-cases (minor leak; helper exists to hide it)
- worker supports both job-based and legacy session-based processing paths (migration state)
Bottom line:
- **Plan alignment:** largely achieved at the capability level, though the API surface has evolved from the plans original endpoint list.
- **PRD alignment:** still intentionally partial (LinkedIn-first subset). Cross-platform automation, scheduled posting, RQx integration, and enterprise workflows remain out of scope / incomplete.
---
## Current Architecture (Observed)
### Surface layer
Surfaces are primarily HTTP routes:
- FastAPI app composition: `app/main.py`
- v1 router aggregation: `app/api/v1/router.py`
- route modules:
- `app/api/v1/profiles.py`
- `app/api/v1/analysis.py`
- `app/api/v1/content.py`
- `app/api/v1/internal.py`
Additional surfaces also exist:
- WebSocket agent surface: `app/main.py``/ws/agent`
- A2A surfaces: `app/a2a/*`
- MCP tool surface: `app/main.py` mounts `/mcp`
### Service layer (orchestration)
Orchestration is primarily represented by:
- Use-cases: `app/use_cases/*`
- Persistence boundaries: `app/repositories/*`
Example orchestration pattern:
- `app/use_cases/enrich_profile.py`:
- loads user + profile via repos (`AccountsRepo`, `ProfilesRepo`)
- calls an external adapter (`BrightDataService`)
- persists changes via repos
- returns the updated ORM object
### Engine layer (pure decision logic)
The engine now has:
- normalized contracts: `app/engine/contracts.py`
- decision engines:
- `app/engine/audit_engine.py`
- `app/engine/brand_score_engine.py`
- `app/engine/persona_engine.py`
- `app/engine/calendar_engine.py`
- `app/engine/draft_engine.py`
### Worker + jobs
- Worker consumes Redis Stream `tasks:social-branding`: `app/adk/worker.py`
- Jobs are normalized and enumerated: `app/jobs/definitions.py`
- Worker supports:
1. **Job path** (new): `job_type` → jobs dispatcher → use-cases
2. **Legacy session path**: agent session-based behavior
See README job summary: `README.md` (“Job system”).
---
## Progress vs prior audit (2026-03-23 → 2026-03-25)
The previous audit described the repo as:
- HTTP-only in practice
- a single application service mixing persistence + orchestration + business logic
- an engine-like set of helpers, but not separated as explicit engine/package boundary
- Redis and worker as scaffolding only
### What has improved substantially
1) **Engine extraction is real**
- New explicit `app/engine/` package
- New normalized boundary models in `app/engine/contracts.py`
This directly addresses the prior audits top architectural mismatch (“no explicit normalized engine contract”).
2) **Service logic is decomposed into use-cases + repositories**
- Routes in `app/api/v1/*` generally call `app/use_cases/*`.
- Use-cases generally rely on repositories for DB access.
This reduces the prior “one large service” problem.
3) **Worker is now an operational path**
- `app/adk/worker.py` supports a job-based path via `job_type`.
- `app/jobs/definitions.py` defines job types and an idempotency key mechanism.
This is stricter and more production-like than the prior “scaffold” characterization.
4) **Schema is migration-managed**
README explicitly states:
- app does not auto-create tables
- Alembic migrations are required
This removes a major “MVP-only” footgun from the earlier audit.
### Verification evidence
- Unit tests: `pytest -q`**106 passed** (2 warnings)
---
## Layering leaks / integration issues (detailed)
### Leak A — Engine depends on `app/services/*` (layer inversion)
**Evidence**
- `app/engine/audit_engine.py` imports `app.services.scoring_service` inside `run_audit()`.
**Why this is a leak**
The intended architecture says engine is pure and should not depend on service/adapters.
Even if `scoring_service.py` is currently pure, it lives in `app/services/`, which is conceptually “above” engine.
**Risk**
- future edits may add I/O, config, or provider calls into `scoring_service.py`
- engine purity becomes fragile and the architecture story becomes ambiguous
**Recommendation**
Move the scoring rules into the engine layer and reverse dependencies:
- rename/move `app/services/scoring_service.py``app/engine/scoring_rules.py` (or similar)
- update `audit_engine.py` to call `app.engine.scoring_rules`
- optionally keep a thin compatibility wrapper in `app/services/scoring_service.py` for external callers
Success criteria:
- `app/engine/*` imports only stdlib + `app.engine.contracts` (+ pydantic)
- no `app.services.*`, no SQLAlchemy, no FastAPI
---
### Leak B — `app/services/` mixes multiple layers (domain logic + adapters + provider orchestration)
**Evidence**
`app/services/` contains:
- domain-like rules logic: `app/services/scoring_service.py`
- external platform adapters:
- `app/services/brightdata_service.py`
- `app/services/scrapetable_service.py`
- AI orchestration / provider layer:
- `app/services/branding_intelligence.py`
- `app/services/ai_service.py`
**Why this matters**
Its not “wrong” operationally, but it weakens the 3-layer presentation (engine/service/surface).
Right now the actual runtime conceptual layers are closer to:
- surfaces
- use-cases (service orchestration)
- engine
- adapters/providers (BrightData/Scrapetable/OpenAI/DSPy)
**Recommendation**
Split by intent:
- `app/engine/` → pure decision logic
- `app/use_cases/` → orchestration
- `app/repositories/` → persistence boundary
- `app/adapters/` (or `app/integrations/`) → brightdata/scrapetable/ai providers
This is mostly a packaging clarity move, but it reduces future layering violations.
---
### Leak C — Surfaces still pass DB sessions directly (minor leak)
**Evidence**
Routes commonly use:
- `session=Depends(get_session)`
- then call use-cases with `execute(session, clerk_id=..., ...)`
Examples:
- `app/api/v1/analysis.py`
- `app/api/v1/profiles.py`
- `app/api/v1/content.py`
There is already a helper intended to hide this:
- `app/api/dependencies.py` defines `provide_use_case(fn)`
**Why it matters**
This makes surfaces slightly “thicker” and exposes infrastructure plumbing.
**Recommendation**
Optional cleanup:
- adopt `provide_use_case()` consistently so route modules dont touch sessions directly
---
### Leak D — Worker supports two execution models (job path + legacy session path)
**Evidence**
- `app/adk/worker.py`:
- job path: `job_type` → jobs dispatcher
- legacy path: `SocialAgentSession` based on `action` / `session_start`
**Why it matters**
Having two paths for “doing work” means:
- idempotency/retry semantics may differ
- auth context may differ
- business invariants can diverge
**Recommendation**
Treat this as an explicit migration state:
- long-term goal: agent/session path should call use-cases (or enqueue jobs) so theres one service boundary
---
## Plan alignment (`docs/plan.md`)
The plan is a LinkedIn-first, individual-only MVP with:
- ingest profile data
- compute Brand Score v1
- persona-based strategy
- content calendar + draft generation
- approval queue + manual publish confirmation
- dashboard exposure
### Capability-level mapping (observed)
1) **Ingest / import**
- URL-first ingestion and refresh flows exist:
- `app/api/v1/profiles.py`
- use-cases: `save_linkedin_url`, `fetch_profile_by_url`, `sync_profile`, `enrich_profile`
- Worker supports `IMPORT_PROFILE` job: `app/jobs/definitions.py`
Status: **Met** (though ingestion method has evolved vs plans “manual JSON import endpoint”).
2) **Audit + Brand Score v1**
- rule-based auditing exists:
- `app/services/scoring_service.py`
- `app/engine/audit_engine.py`
- Brand score engine exists:
- `app/engine/brand_score_engine.py`
- brand score use-case exists: `app/use_cases/recalculate_brand_score.py`
Status: **Met**
3) **Persona + calendar + drafts**
- persona engine: `app/engine/persona_engine.py`
- calendar engine: `app/engine/calendar_engine.py`
- draft engine: `app/engine/draft_engine.py`
- calendar use-case: `app/use_cases/generate_calendar.py`
- worker job: `GENERATE_CALENDAR`
Status: **Met**
4) **Approval queue + publish confirmation**
- use-case exists: `app/use_cases/approval_workflow.py`
Status: **Likely met** (use-case exists, test suite passes broadly), but endpoint-level verification should be confirmed if this is presentation-critical.
5) **Dashboard**
- dashboard use-case: `app/use_cases/get_dashboard.py`
- dashboard state endpoint for ecosystem: `app/main.py``/api/state/{clerk_id}`
Status: **Met**
### Plan checklist items (from plan.md “Review Checklist”)
- Service works without Live LinkedIn OAuth → **Met** (URL-based ingestion)
- LinkedIn is the only live platform in v1 → **Met** (runtime behavior)
- Brand Score does not depend on unavailable metrics → **Met**
- Approval queue blocks publishing until approval → **Likely met** (verify approval endpoints and state transitions if needed)
- Multi-platform and enterprise features stay deferred → **Met**
- Dashboard exposes useful state → **Met**
---
## PRD alignment (`docs/PRD.md`)
PRD describes a broader multi-platform automation loop:
Connect → Collect → Analyze → Generate → Approve → Post → Track → Feed back (Brand Score → RQx)
### What is covered (partial PRD)
- LinkedIn profile analysis exists (rule-based + AI routes)
- Strategy generation exists (`app/api/v1/content.py` and `app/use_cases/generate_content_strategy.py`)
- Approval concept exists (approval workflow use-case)
- Intelligence provider architecture exists (`app/services/branding_intelligence.py`) with heuristic fallback
### What is not covered / missing vs PRD
Not observed in current codebase (and consistent with MVP scope):
- OAuth connect flows per platform
- Cross-platform runtime collection + posting (Instagram/X/YouTube)
- Scheduled posting executors
- Recurring sync cadence engine (daily/48h/weekly) as an orchestrated scheduler
- Brand Score → RQx formula mapping and cross-service event emission
- string search found no `RQx`, `Assessment Service`, or `Pathways Service` integration hooks in `app/**`
- Tone lock and sensitive-topic filtering
- Auto-approve mode (opt-in)
- Engagement automation workflow (draft replies/comments end-to-end)
- Enterprise governance and multi-role approval workflow
PRD alignment conclusion:
- **PRD-complete:** No
- **PRD-partial (LinkedIn-first subset / foundations):** Yes
---
## Acceptance Criteria Coverage Summary
### Plan acceptance criteria (interpreted from `docs/plan.md`)
Met:
- LinkedIn-first, individual-only MVP flow is implemented in current architecture
- ingestion without OAuth dependency is supported
- audit, persona, calendar, drafts, brand score, dashboard exist
- background job path exists and is documented
- migrations required (no implicit schema creation)
Not fully verified in this pass:
- approval queue endpoints + publish confirmation endpoints (use-case exists; verify routes/state transitions if required for demo)
### PRD acceptance criteria (high-level)
Met (foundation-level only):
- analysis + generation surfaces exist
- approval touchpoint exists conceptually
Not met (major PRD features):
- automated cross-platform loop (connect/collect/post/track)
- scheduled posting
- analytics parity + recurring sync
- Brand Score → RQx integration + downstream event emission
- tone lock, sensitive-topic filter
- auto-approve mode
- engagement automation
- enterprise governance workflows
---
## Quality gates (evidence)
- Tests: `pytest -q`**106 passed** (2 warnings)
Warnings:
- Pydantic v2 deprecation warning about class-based Config (non-blocking)
---
## Recommendations (prioritized)
### 1) Fix engine purity (remove layer inversion)
- Move rule-based scoring logic from `app/services/scoring_service.py` into `app/engine/`.
- Update `app/engine/audit_engine.py` to call engine-local scoring.
This is the cleanest, highest-signal architecture fix.
### 2) Clarify adapter/provider layer
- Split `app/services/` into `app/adapters/` (or `app/integrations/`) vs domain logic.
### 3) Thin surfaces further (optional)
- adopt `app/api/dependencies.py::provide_use_case()` so routes dont pass sessions directly.
### 4) Converge worker execution paths
- make legacy session path invoke use-cases (or enqueue jobs) so there is one orchestration boundary.
---
## Bottom line
Compared to 2026-03-23, this repo is now **meaningfully closer** to the desired target architecture:
- explicit engine and normalized contracts
- use-case based orchestration
- worker jobs are functional and documented
The main remaining architecture debt is **layer purity and packaging clarity**, not missing MVP features.

View File

@@ -0,0 +1,376 @@
# Implementation plan — Brand Score: full PRD component model + breakdown
Date: 2026-03-27
Scope: PRD additions item **(1)** (from `prd-additions.md`)
Non-goals (explicit PRD exclusions for this phase): posting, executing actions on platforms, adding new platforms beyond LinkedIn-first.
---
## Checklist (requirements coverage)
- [ ] Add remaining Brand Score components as **first-class computed fields** (not just a single audit-derived score):
- [ ] Content Consistency (20%)
- [ ] Audience Growth (15%)
- [ ] Engagement Rate (15%)
- [ ] Recruiter Visibility (15%)
- [ ] Content Quality (10%)
- [ ] Cross-Platform Consistency (5%) (schema-ready; compute from available platforms only)
- [ ] Store/persist **component breakdown** and PRD-required **“objective, measurable signals”** explanations
- [ ] Implement Brand Score **trend line** (history storage + API response)
- [ ] Implement **v1 proxies + renormalization** for LinkedIn-private analytics gaps
- [ ] Add **metrics snapshot persistence** (followers/connections over time) so Audience Growth + trendline are computable
---
## 1) Outcome + contract
### Inputs
Per `user_id` and a computation window (rolling), compute with:
- LinkedIn profile snapshot: headline/about/experience/skills (as currently ingested)
- Post/activity list over a window (suggest 30 days): timestamps, text, and any available post metrics
- Metrics snapshots over time (if present/collectible): followers/connections, impressions, engagements, profile views, search appearances
- Persona context (if present): target persona/role signals used in content quality and recruiter visibility proxy
**v1 data reality (current repo ingestion):**
- Profile snapshot fields + `followers_count`/`connections_count` are present.
- `activity` exists but is typically limited (date/title/url + sometimes likes/comments).
- Impressions/reach, profile views, and search appearances are typically not available in LinkedIn-first v1; treat as proxy/N.A.
### Outputs
- `brand_score_total` (0100)
- `brand_score_components[]` each with:
- `key` (stable enum)
- `weight` (PRD)
- `score` (0100)
- `weighted_points` (score × weight)
- `signals` (structured numeric strings/values for auditability)
- `explanation` (human-readable, objective/measurable)
- `insufficient_data` (boolean)
- `brand_score_history[]` trendline points (date, total score)
### Error + missing data behavior
Pick **one explicit policy** so scores dont jitter unpredictably:
- **Recommended v1:** *weight renormalization*.
- If component lacks minimum data, mark `insufficient_data=true`.
- Exclude it from total weighting and renormalize remaining weights to sum to 1.0.
- Still return the missing component in breakdown (so UI can display “N/A”).
**v1 proxy rule:** if a PRD metric is not collectible on LinkedIn (e.g., impressions, profile views, search appearances), compute a deterministic proxy where possible; otherwise mark the component `insufficient_data=true` and rely on renormalization.
### Versioning
Persist a scoring version string (e.g. `2026-03-27.v1`) with each snapshot to support future formula tweaks.
---
## 2) Component model (PRD weights + measurable signals)
> Scores are 0100. Each component must produce structured `signals` and a plain-language explanation referencing those signals.
### 2.1 Content Consistency — 20%
**Goal:** consistency of posting frequency + tone consistency over a rolling window.
**Signals (v1):**
- `posts_last_30d`
- `days_between_posts_avg`
- `days_between_posts_stddev`
- `weeks_meeting_target_cadence` (e.g., >=2 posts/week or configured target)
- `tone_label_distribution` (optional v1) or `tone_consistency_score`
**v1 note:** cadence is computable from `activity[].date` if present.
**Important v1 filter:** Bright Data “activity” often includes *interactions* (e.g., “Liked by X”), not just authored posts. Use `activity[].type` (populated from Bright Data `interaction` when available) to **exclude** non-authored items from cadence calculations.
Tone is optional and should be `insufficient_data=true` unless post text is available.
#### Tone consistency (addendum — v1.1 implementation checklist)
We currently score **cadence** deterministically from activity dates; this addendum covers adding the optional “tone consistency” portion without destabilizing totals.
- [ ] Extend ingestion/normalization so activity items include **authored post text** when available
- [ ] Prefer a stable field name in the normalized profile dict (e.g. `activity[].text`).
- [ ] Ensure non-authored items are filtered (continue using `activity[].type/interaction` heuristics).
- [ ] Add tone classification (deterministic-first, AI optional)
- [ ] Add adapter method (or reuse existing AI adapter) to classify tone labels for a post: e.g. `{tone: "educational"|"opinion"|"personal"|"promo"|...}`
- [ ] Cache tone labels per post URL/id when possible to avoid re-scoring.
- [ ] Compute tone consistency signals
- [ ] `tone_label_distribution` (counts per label)
- [ ] `tone_entropy` (or similar) as the numeric signal
- [ ] `tone_consistency_score` mapped 0100
- [ ] If fewer than N posts have text (suggest N=3), mark tone as `insufficient_data=true`.
- [ ] Merge cadence + tone into the existing `content_consistency` score
- [ ] Recommended split: cadence 70%, tone 30% (configurable)
- [ ] Keep overall component deterministic when AI is unavailable:
- [ ] If AI tone classification fails, fall back to `insufficient_data=true` for tone and score cadence only.
- [ ] Update explanation string to include tone when scored
- [ ] Example: “Cadence variance is X days; tone consistency is Y/100 across N posts.”
- [ ] Add tests
- [ ] Test cadence-only path remains unchanged.
- [ ] Test tone-scored path produces stable distribution + score.
**Computation idea (v1 deterministic + optional AI):**
- Frequency score derived from cadence stability:
- reward meeting minimum weekly target
- penalize high variance in gaps
- Tone consistency (optional): classify each post tone (adapter AI), compute entropy / variance; map to 0100.
**Explanation template:**
- “You posted {posts_last_30d} times in 30 days. Cadence variance is {stddev} days; {weeks_meeting_target_cadence}/4 weeks meet target.”
### 2.2 Audience Growth — 15%
**Goal:** follower/connection growth rate over last 30 days.
**Signals:**
- `followers_start_30d`
- `followers_end_30d`
- `follower_growth_abs`
- `follower_growth_rate`
**v1 requirement:** this component needs historical follower counts. Implement via metrics snapshots (see §3.3).
**Computation (v1):**
- `growth_rate = (end - start) / max(start, 1)`
- Map to 0100 using bands (configurable), e.g.:
- <=0% → 10
- 01% → 40
- 13% → 70
- 36% → 85
- >6% → 95
**Explanation:**
- “Followers changed from {start} → {end} (+{abs}, {rate:.1%}) in 30 days; target band is {target_band}.”
### 2.3 Engagement Rate — 15%
**Goal:** likes/comments/shares/saves as % of reach.
**Signals:**
- `posts_counted`
- `impressions_total` (or `reach_total` if you have it)
- `engagements_total`
- `engagement_rate_weighted_avg`
- `engagement_rate_p50` / `p75` (optional)
**Computation (v1):**
- Prefer weighted average: `sum(engagements)/sum(impressions)` across posts with impressions.
- Guardrails for low denom.
**v1 LinkedIn-first proxy:** if impressions/reach arent available, use a deterministic proxy:
- `engagements_total = sum(likes + comments)` across recent activity items with those fields
- `engagements_per_post_avg = engagements_total / max(posts_counted, 1)`
- Optional normalization: `engagements_per_post_per_1k_followers`
If engagement signals are missing/too sparse, mark `insufficient_data=true` and renormalize.
**Important v1 filter:** only count *authored posts* (exclude “liked/commented/shared by user” items based on `activity[].type`).
**Explanation:**
- “Avg engagement rate is {rate:.2%} across {posts_counted} posts; benchmark target band {target_band}.”
### 2.4 Recruiter Visibility — 15%
**Goal:** profile appearance rate in recruiter/talent searches.
**Signals (best effort LinkedIn-first):**
- Preferred if collectible:
- `search_appearances_7d`, `search_appearances_30d`
- `profile_views_7d`, `profile_views_30d`
- Proxy if not collectible:
- `keyword_coverage_score` (0100)
- `missing_keywords_count`
**Computation (v1):**
- If search appearances/profile views available: score by percentile bands.
- Else: compute proxy keyword coverage vs target role/persona keyword set.
**v1 default:** treat search appearances/profile views as unavailable and use keyword coverage proxy.
**Explanation:**
- “Search appearances (7d): {x}. Keyword coverage {coverage}/100; missing {n} high-signal recruiter keywords.”
### 2.5 Content Quality — 10%
**Goal:** AI-assessed relevance/originality/alignment to persona framework.
**Signals:**
- `ai_quality_score_avg`
- `ai_relevance_avg` (optional detail)
- `ai_originality_avg` (optional detail)
- `ai_persona_alignment_avg` (optional detail)
- `low_quality_flags` (e.g., repetitive template, too short)
**Computation (v1):**
- Use AI adapter to score posts (sample last N posts).
- Average to 0100; apply small penalties for repeated/low-effort patterns.
**v1 fallback:** if post text isnt collectible, score using profile text (headline + summary + recent roles) and reflect that in `signals`.
**Explanation:**
- “Quality score {score}/100 across {n} posts: relevance {r}/100, originality {o}/100, persona alignment {p}/100.”
### 2.6 Cross-Platform Consistency — 5% (schema-ready)
**Goal:** messaging/voice alignment across connected platforms.
**Signals:**
- `connected_platforms`
- `platforms_scored`
- `cross_platform_similarity` (if >1 platform)
**Computation (v1):**
- If only LinkedIn connected: mark `insufficient_data=true` and exclude via renormalization.
- If multiple: compare embedding similarity of bios/headlines + recent posts themes.
**Explanation:**
- “Only LinkedIn connected; cross-platform consistency isnt scored yet.”
---
## 3) Persistence + history (trend line)
### 3.1 Storage model
Add a snapshot table to store history and component breakdown for auditability.
**Recommended table:** `brand_score_snapshots`
- `id`
- `user_id`
- `platform` (string/enum)
- `window_start`, `window_end`
- `score_total` (numeric)
- `components_json` (JSON/JSONB)
- `scoring_version` (string)
- `created_at`
Also store a “latest” summary on the user profile (fast reads):
- `latest_brand_score_total`
- `latest_brand_score_components_json`
- `latest_brand_score_calculated_at`
### 3.2 Trendline
- Provide daily points (last N days).
- If multiple snapshots/day: use latest per day (simple, stable).
### 3.3 Metrics snapshots (Audience Growth input)
Add a small metrics history table so we can compute change-over-time deterministically.
**Recommended table:** `social_metrics_snapshots`
- `id`
- `user_id`
- `platform` (string/enum; v1 = `linkedin`)
- `followers_count` (int nullable)
- `connections_count` (int nullable)
- `captured_at` (timestamp)
**Capture policy (v1):**
- Insert a snapshot after each successful LinkedIn sync.
- Optional dedupe: keep at most 1 snapshot/day per user+platform.
---
## 4) Engine design (code structure)
### 4.1 Orchestrator
In `app/engine/brand_score_engine.py` (or equivalent), implement:
- `compute_brand_score(user_id, platform, window_days=30) -> BrandScoreResult`
- `compute_and_persist_brand_score(...) -> BrandScoreSnapshot`
### 4.2 Component functions
Create pure functions (easy to test):
- `score_content_consistency(data) -> ComponentResult`
- `score_audience_growth(data) -> ComponentResult`
- `score_engagement_rate(data) -> ComponentResult`
- `score_recruiter_visibility(data) -> ComponentResult`
- `score_content_quality(data) -> ComponentResult`
- `score_cross_platform_consistency(data) -> ComponentResult`
### 4.3 Config + thresholds
Centralize mapping bands and targets so theyre easy to tune:
- engagement target bands
- growth target bands
- cadence target
- minimum sample sizes (e.g., >=3 posts for some components)
---
## 5) API changes
### 5.1 Endpoints (or dashboard response augmentation)
Add (or extend existing dashboard routes):
1) `GET /brand-score/latest`
- Returns: total + components breakdown + `scoring_version` + `window`.
2) `GET /brand-score/trend?days=30`
- Returns: array of `{date, score_total}` (optionally include component totals later).
### 5.2 Response schemas
Add Pydantic models:
- `BrandScoreComponentBreakdown`
- `BrandScoreSnapshotResponse`
- `BrandScoreTrendResponse`
---
## 6) Triggering computations
Compute snapshot when inputs change.
**Recommended triggers:**
- After each LinkedIn sync job completes
- Optionally: nightly job (backup) to ensure fresh trendline
Implementation:
- Hook into job dispatcher / sync pipeline to call `compute_and_persist_brand_score(user_id, "linkedin")`.
**v1 addition:** after LinkedIn sync, also write a `social_metrics_snapshots` row (followers/connections) so Audience Growth works.
---
## 7) Tests (minimum set)
Add unit tests in `tests/` to stabilize the scoring math:
1) `test_brand_score_components_happy_path`
- Fake dataset with posts + metrics
- Assert all 6 component keys present
- Assert weights consistent with PRD
- Assert total score within expected range and deterministic
2) `test_brand_score_missing_data_renormalization`
- Omit recruiter visibility metrics & cross-platform
- Assert `insufficient_data` flagged
- Assert total calculation uses renormalized weights
3) `test_brand_score_snapshot_persistence`
- Compute-and-persist writes a snapshot and updates “latest” summary
4) `test_metrics_snapshots_enable_audience_growth`
- Insert two snapshots in-window
- Assert the Audience Growth component derives start/end from snapshots
---
## 8) Execution steps (recommended order)
1) Add DB migration(s): `brand_score_snapshots` + latest fields on user summary
1b) Add DB migration: `social_metrics_snapshots`
2) Implement/extend scoring engine with component spec + versioning
3) Add repository methods for snapshot insert + trend queries
4) Add API endpoints/schemas for latest + trendline
5) Wire compute trigger after sync
6) Add tests and make them green
---
## 9) Notes / open questions (non-blocking)
- Recruiter visibility and search appearances might be hard to collect reliably without LinkedIn API access; v1 can use a proxy keyword coverage score.
- Engagement rate impressions/reach may be unavailable on LinkedIn-first v1; use engagement proxies or mark insufficient data + renormalize.
- Cross-platform consistency should be marked “insufficient data” unless multiple platforms are connected.
- If you already have brand score summary fields on `social_users`, reuse them; otherwise add them.

View File

@@ -0,0 +1,244 @@
# Implementation Plan: Brand Score → RQx mapping + events
Date: 2026-03-27
Scope source: `docs/prd-additions.md` → section **“2) Brand Score → RQx mapping + events”**
Out of scope: Posting/automation to platforms; adding new platforms.
---
## ✅ Requirements checklist (PRD)
- [ ] Compute & store **RQx contribution** as: `Brand Score × 0.4`
- [ ] Ensure recalculation runs **after every platform sync** (LinkedIn daily in PRD)
- [ ] Emit update when Brand Score changes by **5+ points**, including before/after + metadata
- [ ] Persist and expose Brand Score history for the dashboard (trendline)
---
## Tiny contract (what well build)
### Inputs
- `social_user_id`
- `platform` (initially `linkedin`)
- `sync_context` metadata (at least: `sync_job_id`, `sync_started_at`, `sync_finished_at`, `source`)
### Computation
- `brand_score` (0100) from the active Brand Score engine (v1/v2)
- `rqx_contribution = brand_score * 0.4`
### Outputs
1. **Current state** persisted on the user (fast reads):
- `brand_score` (and updated timestamp)
- `rqx_contribution` (and updated timestamp)
2. **History** row appended each recompute:
- before/after values + delta
- metadata (platform, sync_job_id, engine version)
3. **Event** emitted only when threshold met:
- condition: `abs(brand_score_after - brand_score_before) >= 5`
### Error handling expectations
- If sync fails → do not recompute.
- If recompute fails → do not partially write; record failure on the job.
- If no previous score exists → write current + history. Event emission rule should be explicit (see Decisions).
---
## Decisions to lock (before coding)
1. **Engine selection**
- Confirm whether `app/engine/brand_score_engine.py` or `app/engine/brand_score_v2_engine.py` is source-of-truth.
- Add `engine_version` to history metadata to prevent confusion during the migration period.
2. **First-time score event behavior**
- Option A: Do **not** emit threshold event on first compute.
- Option B: Emit `brand_score.initialized` as a separate event.
3. **Event delivery mechanism**
- If an existing emitter/bus exists (e.g., `app/adk/emitter.py`), reuse it.
- If not, implement an **Outbox table** (durable events) and a worker to dispatch them.
---
## Prerequisites / gaps to confirm in the repo
These should be verified before implementation to avoid rework:
1. **Where Brand Score and summaries are stored today**
- Migrations suggest existing work (e.g., brand score “summary”, “snapshots”, “metrics history”). Confirm actual tables/columns.
2. **Platform sync lifecycle hook**
- Identify the “sync completed successfully” point for LinkedIn.
- We need a stable callback/hook to trigger recomputation exactly once per successful sync.
3. **Existing RQx representation**
- There are tests around the RQx formula. Confirm whether theres a persisted “RQx” score model already.
- Ensure `rqx_contribution` doesnt conflict with other RQx computation.
4. **History API shape already used by dashboard**
- If the dashboard already expects a trendline format, align the endpoint/DTO to it.
---
## Data model plan
### A) Current state (likely on `social_users`)
Add/confirm:
- `brand_score` (numeric)
- `rqx_contribution` (numeric)
- `brand_score_updated_at` (datetime)
Indexes:
- `(id)` already
- optional: `(brand_score_updated_at)` if filtered queries are common
### B) History table (trendline + auditing)
If not already present, add a new table like `brand_score_history`:
- `id` (pk)
- `social_user_id` (fk)
- `platform` (string)
- `brand_score_before` (numeric, nullable)
- `brand_score_after` (numeric, not null)
- `rqx_before` (numeric, nullable)
- `rqx_after` (numeric, not null)
- `delta` (numeric, not null)
- `sync_job_id` (string/uuid, nullable)
- `engine_version` (string)
- `metadata` (json)
- `created_at` (datetime)
Indexes:
- `(social_user_id, created_at desc)`
- `(platform, created_at desc)` (optional)
Note: If an existing “snapshots/history” table already exists, extend it rather than duplicating.
---
## Service boundary (single place to do it right)
Create/extend a service method:
`BrandScoreService.recalculate_and_persist(social_user_id, platform, sync_context) -> RecalcResult`
Responsibilities:
1. Load current user and previous score.
2. Compute new `brand_score` via engine.
3. Compute `rqx_contribution = brand_score * 0.4`.
4. Persist updates:
- update current fields on user row
- append history row
5. Event threshold logic:
- if previous exists and `abs(delta) >= 5` → emit event
Why this matters:
- Keeps sync jobs thin.
- Prevents duplicated threshold logic across code paths.
---
## Wiring: recompute after every platform sync
### Where to hook
- Identify the LinkedIn sync job/task entrypoint (likely under `app/jobs/` or `app/services/`).
### When to hook
- **After** all sync writes are committed (so the score uses fresh data).
- Prefer same DB session/transaction boundaries when reasonable.
### Backfill / catch-up
- Add a safe admin-only/manual job to recompute for all users (optional, but useful after schema change).
---
## Event design
### Event name
- `brand_score.updated` (threshold-triggered)
- optional: `brand_score.initialized`
### Payload (PRD-required)
- `social_user_id`
- `platform`
- `brand_score_before`
- `brand_score_after`
- `brand_score_delta`
- `rqx_before`
- `rqx_after`
- `computed_at`
- `sync_job_id` (if present)
- `engine_version`
- `metadata` (freeform)
### Delivery
- If existing emitter exists: publish immediately.
- If not: write to durable outbox and dispatch asynchronously.
---
## API changes: trendline exposed for dashboard
### Endpoint (example)
- `GET /v1/social-users/{id}/brand-score/history?days=30`
### Response shape (example)
- `current`: `{ brand_score, rqx_contribution, updated_at }`
- `trendline`: array of `{ date, brand_score, rqx_contribution }`
Implementation notes:
- Ensure efficient paging/limit.
- Default window (e.g., 30 or 90 days).
---
## Tests (minimum set)
1. **Unit**: computes `rqx_contribution = brand_score * 0.4`
2. **Unit**: emits event only when `abs(delta) >= 5`
3. **Unit**: first-time compute behavior (explicit rule)
4. **Integration-ish**: “sync completed” triggers recalculation call
5. **API**: history endpoint returns ordered trendline
---
## Step-by-step execution plan
1. **Recon** (fast repo check)
- Confirm existing tables/migrations for brand score history/snapshots.
- Identify sync pipeline completion point.
- Identify current event/emitter infra.
2. **Schema**
- Add missing columns/tables for `rqx_contribution` + history fields.
- Add indexes.
3. **Service**
- Implement `recalculate_and_persist`.
- Add tests.
4. **Sync wiring**
- Call service after LinkedIn sync success.
- Add a test around the hook.
5. **Events**
- Implement emission (or outbox write).
- Test threshold behavior.
6. **API**
- Add/extend endpoint for trendline.
- Add tests.
7. **Backfill (optional but recommended)**
- Add a job/CLI path to compute and write missing `rqx_contribution` + history.
---
## Acceptance criteria
- On every successful LinkedIn sync, Brand Score recomputes and persists.
- `rqx_contribution` is always consistent with `brand_score * 0.4`.
- History shows a trendline (at least daily points or per-sync points).
- When Brand Score changes by **≥ 5**, an event is emitted with complete before/after + metadata.
- Unit tests cover formula + threshold + first-time behavior.

View File

@@ -0,0 +1,340 @@
# Implementation Plan: LinkedIn Profile Rewrite Variants + User Selection (Draft-only)
Date: 2026-03-27
Source: `docs/PRD.md` → “5.1 LinkedIn → Profile Rewrite” + `docs/prd-additions.md` item (3)
Scope: **Generate → Approve (select)** only. **No posting**. **No LinkedIn write-back**.
---
## Goals (what were shipping)
Implement a draft-only workflow that:
1. Generates rewrite options for a users LinkedIn profile.
2. Returns them via API for review.
3. Lets the user select/approve one option per section.
4. Persists both the generated variants and the users selection for dashboard/UI use.
PRD-required deliverables:
- Headline: **3 variants**
- About section: optimized version(s)
- Experience bullet points: per role
- Skills list: mapped to **Q-Score signals** + **target JD keywords**
---
## Non-goals / explicit exclusions
- No automated posting.
- No executing edits on LinkedIn.
- No new platform support (LinkedIn-first only).
---
## Existing repo capabilities we will reuse
### AI generation primitives (already present)
The repo already includes AI adapter functions in `app/adapters/ai_service.py`:
- `improve_headline(profile_data, current_headline, context)`
- `improve_summary(profile_data, current_summary, context)`
- `improve_experience(profile_data, experience_entry, context)`
- `suggest_skills(profile_data, context)`
These are thin wrappers over `BrandingIntelligenceEngine` and should be reused to avoid duplicating prompt logic.
### LinkedIn profile persistence (already present)
`app/services/brand_score_recalc_service.py` demonstrates that a user has persisted LinkedIn profiles via `user.linkedin_profiles` and that a “latest profile” can be selected using `last_synced_at`.
### Approval workflow patterns (already present)
Theres a state-machine style approval flow in `app/use_cases/approval_workflow.py` (currently for content drafts). Well mirror the same ergonomics for rewrite drafts (approve/reject), but with rewrite-specific statuses.
---
## Proposed domain contract (inputs/outputs)
### Inputs (Generate)
- `social_user_id` (derived from auth)
- `platform` = `linkedin`
- `target_role`: string (e.g., “Senior Product Manager”)
- `target_jd_keywords`: list[string] (0..N)
- Optional: `context` string (free-form notes like “targeting fintech”, “prefer concise voice”)
### Output (Draft)
A persisted “rewrite draft” with generated variants and stable IDs so frontends can select precisely.
Recommended structure (API DTO / Pydantic schema):
- `id` (uuid)
- `user_id`
- `platform`
- `source_linkedin_profile_id` (the snapshot/profile record used)
- `inputs`: `{ target_role, target_jd_keywords, context }`
- `generated`:
- `headline_variants`: **3** items
- `about_variants`: 12 items (recommend 2 for user choice)
- `experience_variants`: per role, list of bullet options
- `skills_suggestions`: ranked list with provenance tags
- `selection` (nullable until approved)
- `status`: `draft | approved | rejected | superseded`
- `created_at`, `updated_at`
---
## Data model & migrations
### Option A (recommended): JSON-first, minimal tables
Add a new table, e.g. `linkedin_profile_rewrites`:
- `id` UUID PK
- `user_id` FK (or clerk id; follow existing account conventions)
- `platform` string (`linkedin`)
- `source_linkedin_profile_id` FK (or just store the profile UUID)
- `inputs_json` JSONB
- `generated_json` JSONB
- `selection_json` JSONB nullable
- `status` enum/string
- `created_at` / `updated_at`
Pros: fastest to ship; easy to evolve.
### Option B: normalized variants tables
Add separate tables for variants and selections. Pros: easier analytics/search. Cons: more work now.
**Decision:** Start with Option A unless we have an immediate need to query variants independently.
### Migration tasks
- Create Alembic revision adding the new table and any needed enums.
- Indexes:
- `(user_id, created_at desc)`
- `(user_id, status)`
---
## Generation service design
Add a new service, e.g. `app/services/linkedin_profile_rewrite_service.py`.
### Responsibilities
1. Load the **latest** connected LinkedIn profile for the user (same selection logic as BrandScore recalc).
2. Build `profile_data` dict in the same shape used by AI functions.
3. Generate variants:
#### Headline: 3 variants
Implementation approach:
- Use `ai_service.improve_headline` three times with different context “styles” to force diversity:
1) Recruiter/keyword-forward
2) Achievement/value-prop
3) Persona/voice-forward
Additionally, enforce:
- Char limit validation (keep within a safe LinkedIn headline cap)
- Deduplication (variants must be meaningfully different)
#### About: optimized version(s)
- Use `ai_service.improve_summary` to produce 2 variants (recommended).
- Enforce max length.
#### Experience bullets: per role
- For each experience entry, call `ai_service.improve_experience` with:
- target role
- keywords
- “prefer metrics and outcomes”
Store results per role.
#### Skills: mapped to Q-Scores + JD keywords
- Use `ai_service.suggest_skills` with context containing:
- target role
- JD keywords
- any available Q-score signals (see prerequisites below)
Then post-process:
- Normalize (title case / trim)
- Deduplicate
- Tag provenance for each skill: `jd | qscore | both | ai`
### Explainability (“objective signals”)
While PRD item (3) doesnt explicitly demand explanations, it helps UX and aligns with later recruiter visibility features.
For each variant include:
- `keywords_used`: list[string]
- `rationale`: short string
---
## API endpoints
Add routes under `app/api/v1/` (exact module placement should match existing routing conventions).
### 1) Generate
`POST /v1/linkedin/profile-rewrite/generate`
Body:
- `target_role`
- `target_jd_keywords`
- optional `context`
Response: rewrite draft DTO.
### 2) Fetch by id
`GET /v1/linkedin/profile-rewrite/{rewrite_id}`
Response: rewrite draft DTO.
### 3) Approve / select
`POST /v1/linkedin/profile-rewrite/{rewrite_id}/approve`
Body (selection contract):
- `headline_variant_index` or `headline_variant_id`
- `about_variant_index` or `about_variant_id`
- `experience_selection`: per role key, chosen bullets (either “accept all” or per-bullet indices)
- `skills_final`: final list of skills the user wants
Response: updated rewrite DTO with `status=approved` and non-null `selection`.
### 4) Reject (optional but recommended)
`POST /v1/linkedin/profile-rewrite/{rewrite_id}/reject`
Body: optional feedback.
---
## State machine & lifecycle
Suggested statuses:
- `draft`: generated, awaiting decision
- `approved`: selection persisted
- `rejected`: user rejected (optional feedback)
- `superseded`: a newer draft was generated; keep old one for audit
Rules:
- Approve only allowed from `draft`.
- Reject only allowed from `draft`.
- Generating a new draft can mark older `draft` rows as `superseded` (optional, but recommended).
---
## Prerequisites / missing pieces to confirm before implementing
These are required to meet PRD item (3) fully and cleanly:
1) **Target role + JD keywords source**
- We need a stable way to supply `target_role` and `target_jd_keywords`.
- If not already stored in DB, well require the frontend/client to pass them in the `generate` request.
2) **Q-Score signals beyond a single number**
- “Skills list mapped to Q-Scores” implies we can access either:
- a Q-score category breakdown, or
- a list of validated skill signals.
- If current Q-score integration only returns an aggregate score, we should define a short-term mapping strategy:
- Treat JD keywords as first-class and tag them as `jd`
- Tag AI-suggested skills as `ai`
- Add `qscore` provenance only when breakdown is available
3) **Stable LinkedIn profile snapshot identifier**
- We can already pick the latest `linkedin_profiles` record.
- We must ensure we can store a stable `source_linkedin_profile_id` (UUID) and that its available in the model.
4) **AI engine supports deterministic structured outputs**
- Current AI functions return `dict`. Well need to validate:
- headline output includes a `headline` string (or similar)
- summary output includes `summary`
- experience output includes bullet list
- skills output includes list
- If current outputs are not structured enough, well add a thin normalization layer in the rewrite service.
---
## Testing plan
Add tests in `tests/` that cover:
1) **Variant counts & structure**
- Generate returns exactly **3** headline variants.
- About returns at least 1 variant (prefer 2).
- Experience returns entries for each role.
2) **Approval persistence**
- Approve endpoint updates status to `approved`.
- Selection is persisted and returned.
3) **Ownership / auth**
- Users cant approve/fetch drafts they dont own.
4) **Idempotency & superseding**
- Generating multiple drafts for the same user creates multiple rows.
- (If implemented) older drafts become `superseded`.
---
## Rollout notes
- Keep endpoints feature-flagged if you already have feature flag patterns.
- Log generation/approval events without leaking secrets.
---
## Acceptance criteria
1) **Generate**
- Given a user with a connected LinkedIn profile, calling `POST /v1/linkedin/profile-rewrite/generate` returns a persisted draft containing:
- Headline variants: **exactly 3**
- About variants: **>= 1**
- Experience rewrites: per experience role in the source profile
- Skills suggestions: list includes JD keywords when provided
2) **Approve (user selection)**
- Calling `POST /v1/linkedin/profile-rewrite/{id}/approve` persists the selection and changes status to `approved`.
- Approved draft is retrievable via `GET /v1/linkedin/profile-rewrite/{id}` with `selection` populated.
3) **Draft-only**
- No endpoint performs posting or any platform write-back.
- No code path attempts to modify LinkedIn.
4) **Security/ownership**
- Users cannot access or approve drafts they dont own.
5) **Regression safety**
- Existing content approval workflow is unaffected.
- Existing Brand Score recalculation remains unaffected.
---
## Final implementation checklist
- [ ] Confirm where/how `target_role` and `target_jd_keywords` will be sourced (request-only vs persisted profile settings).
- [ ] Confirm Q-score breakdown availability; decide interim provenance strategy if breakdown is missing.
- [ ] Add DB model(s) + Alembic migration for rewrite drafts.
- [ ] Add Pydantic schemas for request/response.
- [ ] Implement `linkedin_profile_rewrite_service` using `app/adapters/ai_service.py` primitives.
- [ ] Add API routes: generate, get by id, approve (and optional reject).
- [ ] Add tests for generation counts, approval persistence, ownership.
- [ ] Run unit tests and ensure green.

View File

@@ -0,0 +1,184 @@
# Execution playbook — migrate Brand Score v1 → v2 (component model)
Date: 2026-03-27
Scope: replace audit-derived Brand Score v1 with PRD component-model Brand Score v2.
This doc is the **step-by-step execution order** for completing the migration, plus a **final verification checklist** to confirm nothing still depends on v1.
---
## What were migrating (quick references)
### v1 (legacy)
- **Engine:** `app/engine/brand_score_engine.py`
- Function: `compute(audit, extra_profile_data)`
- Output: `BrandScoreResult` with `brand_score`, `grade`, `strengths`, `quick_wins`
### v2 (target)
- **Engine:** `app/engine/brand_score_v2_engine.py`
- Function: `compute_v2(inputs, ...)`
- Output: `BrandScoreV2Result` with `brand_score_total`, `components[]`, `scoring_version`, `window_*`
- **Persistence wrapper (canonical path):** `app/services/brand_score_service.py::compute_and_persist_v2()`
- Writes:
- Snapshot row (`brand_score_snapshots`)
- Cache (`social_users.brand_score_summary` + `social_users.brand_score_latest_calculated_at`)
### Known v1 call sites to remove
- `app/use_cases/run_profile_analysis.py`
- Imports and calls v1 compute: `from app.engine.brand_score_engine import compute as compute_brand_score`
- Writes legacy cache keys: `{"brand_score": ..., "brand_grade": ...}`
- `app/use_cases/recalculate_brand_score.py`
- Imports and calls v1 compute
- Writes legacy cache keys
- `app/use_cases/get_analysis_view.py`
- References `BrandScoreEngine` (verify if legacy/unused and migrate/remove)
### Confirmed v1 usage map (what actually hits prod today)
This section is here so we can migrate with confidence and not miss a real runtime path.
#### Production (API)
- `POST /api/v1/analysis/profile/{profile_id}`
- Route: `app/api/v1/analysis.py::run_profile_analysis`
- Use-case: `app/use_cases/run_profile_analysis.py::execute`
- v1 call: inside `execute()`
- `from app.engine.brand_score_engine import compute as compute_brand_score`
- `brand = compute_brand_score(audit, profile_data)`
#### Production (worker job)
- Job type: `recalculate_brand_score`
- Dispatcher: `app/jobs/dispatcher.py::_handle_recalculate_brand_score`
- Use-case: `app/use_cases/recalculate_brand_score.py::execute`
- v1 call: `brand = compute_brand_score(audit, profile_data)`
#### Non-production (tests/docs)
- Tests: `tests/test_engine.py`
- Imports v1 compute and asserts legacy outputs.
- Must be migrated/removed before deleting v1.
- Docs: multiple references (this plan + architecture docs)
- No runtime impact, but keep in sync with the final migration state.
---
## Execution order ✅
### 0) Pre-flight (dont change behavior yet)
- [ ] Confirm DB migrations are present and applied in dev:
- [ ] `brand_score_snapshots`
- [ ] `social_metrics_snapshots`
- [ ] `social_users.brand_score_latest_calculated_at`
- [ ] Confirm v2 endpoints work without v1:
- [ ] `GET /brand-score/latest`
- [ ] `GET /brand-score/trend`
### 1) Introduce a migration flag (safe rollout)
- [ ] Add a settings/env flag (example name): `BRAND_SCORE_VERSION=v2|v1`
- [ ] Default should be **v2**.
- [ ] Keep `v1` only as a temporary fallback.
### 2) Stop writing the legacy v1 cache shape (make v2 the source of truth)
Target: only v2 writes the **canonical** cache and snapshot.
- [ ] Update `app/use_cases/run_profile_analysis.py`
- [ ] Remove/avoid calling `app.engine.brand_score_engine.compute()`
- [ ] Ensure it calls **only** `compute_and_persist_v2()` when the flag is v2
- [ ] Ensure `social_users.brand_score_summary` is not overwritten with legacy keys after v2 runs
- [ ] Update `app/use_cases/recalculate_brand_score.py`
- [ ] Remove/avoid calling v1 compute
- [ ] Return brand score value from v2 total (`brand_score_total`) for any callers expecting a number
- [ ] Ensure it doesnt overwrite the v2 cache shape
- [ ] Update/verify `app/use_cases/get_analysis_view.py`
- [ ] If it still reads v1 fields (`brand_score`, `grade`), migrate it to read v2 cache
- [ ] If it constructs or uses a separate BrandScoreEngine abstraction, collapse it onto v2
### 3) Update eventing/delta logic to compare v2 totals
If you emit `brand_score.delta` events anywhere:
- [ ] Change “before/after” comparison to use:
- `brand_score_total` (v2) from `social_users.brand_score_summary`
- [ ] Keep the same delta threshold (>= 5) unless PRD says otherwise
- [ ] Ensure the computed `rqx_contribution` continues to be derived from the total (v2 total)
### 4) Ensure metrics snapshots are captured (audience growth + trend stability)
- [ ] Verify the capture points write `social_metrics_snapshots` after successful sync/import:
- [ ] `app/use_cases/sync_profile.py`
- [ ] `app/use_cases/import_profile.py`
- [ ] Ensure the “at most 1/day per user+platform” behavior remains (via `MetricsRepo.upsert_daily_snapshot()`)
### 5) Backfill (optional but recommended)
- [ ] Create a one-off job/script to backfill:
- [ ] `social_metrics_snapshots` (if missing)
- [ ] `brand_score_snapshots` for last N days (or at least one snapshot per user)
- [ ] Confirm `GET /brand-score/trend` returns non-empty results for existing users
### 6) Remove v1 usage (+ cleanup)
- [ ] Remove imports/usages of v1 engine from all use-cases
- [ ] Remove “legacy” writes to `social_users.brand_score_summary` keys:
- `brand_score`, `brand_grade`
- [ ] Keep `GET /brand-score/latest` backward-compatible temporarily (it already supports both shapes)
- [ ] After a confidence window:
- [ ] Delete or archive `app/engine/brand_score_engine.py`
- [ ] Remove v1 compatibility branch from `app/use_cases/get_brand_score_latest.py`
### 7) Verify wiring is clean (routes + worker)
These are the two *runtime* paths that must be free of v1 imports before you can claim the migration is complete.
- [ ] API path no longer imports v1:
- [ ] `app/use_cases/run_profile_analysis.py` has no `brand_score_engine` import
- [ ] `POST /api/v1/analysis/profile/{profile_id}` still succeeds and returns expected payload
- [ ] Worker path no longer imports v1:
- [ ] `app/use_cases/recalculate_brand_score.py` has no `brand_score_engine` import
- [ ] `JobType.RECALCULATE_BRAND_SCORE` job still succeeds and updates v2 snapshot + cache
---
## Final verification checklist (done = migration complete)
### Codebase checks
- [ ] No remaining imports of v1 engine:
- [ ] `from app.engine.brand_score_engine import ...` is gone
- [ ] No references to `BrandScoreEngine` remain unless its v2-only
- [ ] `social_users.brand_score_summary` is written in **exactly one place**:
- [ ] `app/services/brand_score_service.py::compute_and_persist_v2()`
- [ ] No code overwrites `brand_score_summary` with legacy keys after v2 runs
### Data shape checks (runtime)
- [ ] `GET /brand-score/latest` returns:
- [ ] `brand_score_total`
- [ ] `components[]` (6 keys)
- [ ] `scoring_version`
- [ ] `window`
- [ ] `GET /brand-score/trend` returns daily points from `brand_score_snapshots`
- [ ] New sync/import actions write `social_metrics_snapshots` for the user
### Scoring behavior checks
- [ ] Renormalization is stable when a component lacks data:
- [ ] missing components are marked `insufficient_data=true`
- [ ] total score remains in 0100 and doesnt crash
### Test coverage checks
- [ ] Unit tests cover v2 engine (already present)
- [ ] Add/green: persistence + cache update tests:
- [ ] snapshot row created
- [ ] cache updated in v2 shape
- [ ] Add/green: delta/eventing compares v2 totals

File diff suppressed because it is too large Load Diff

158
social_branding/plan.md Normal file
View File

@@ -0,0 +1,158 @@
# Social Branding Service Plan
## Mission
Build a LinkedIn-first, individual-only social branding MVP that can ingest profile data, compute Brand Score v1, generate persona-based strategy and content plans, manage an approval queue, and expose progress back to the GrowQR ecosystem.
## Locked Scope
### In scope tonight
- individual service only
- LinkedIn-first profile import/audit flow
- manual import or adapter fallback instead of hard OAuth dependency
- persona selection from pathway goal/archetype context
- Brand Score v1
- content calendar generation
- draft generation for LinkedIn
- approval queue
- posting state machine and manual/export-based publish completion
- dashboard and analytics snapshots
- event emission for Brand Score updates
### Explicitly deferred
- enterprise social branding
- Instagram, X, YouTube runtime support
- real auto-posting to live platforms
- full engagement automation
- recruiter search visibility integrations that depend on unstable APIs
- multi-platform analytics parity
## Implementation Decisions
- LinkedIn is the only live platform for v1. Other platforms remain schema-ready only.
- Support manual JSON/import or URL-backed profile snapshot ingestion so the service is not blocked on OAuth.
- Brand Score v1 must normalize to available LinkedIn data. Do not block on missing cross-platform metrics.
- The publish step may be manual-confirmed: generate final copy and mark it posted when the user confirms it was used.
- Use deterministic templates for the 80% toolkit and limited AI generation only for the 20% dynamic layer.
## Domain Model
- `social_accounts`
- `social_profile_snapshots`
- `brand_scores`
- `persona_strategies`
- `content_calendar_items`
- `content_drafts`
- `approval_queue`
- `analytics_snapshots`
- `engagement_drafts`
## Core APIs
- `POST /api/v1/accounts/linkedin/import`
- `POST /api/v1/persona/select`
- `POST /api/v1/brand-score/recalculate`
- `GET /api/v1/dashboard/{user_id}`
- `POST /api/v1/content-calendar/generate`
- `GET /api/v1/content-calendar/{user_id}`
- `POST /api/v1/drafts/generate`
- `POST /api/v1/approval-queue/{item_id}/approve`
- `POST /api/v1/approval-queue/{item_id}/reject`
- `POST /api/v1/approval-queue/{item_id}/regenerate`
- `POST /api/v1/publish/{item_id}/confirm`
## Pathways Dependency
Consume or mock:
- target role
- pathway milestone events
- goal/persona hints
- optional archetype
- optional Q-score changes
Use those to select persona strategy and dynamic content triggers.
## Phase Plan
### Phase 1: Foundations
- [x] Replace template domain with social profile/content models
- [x] Define persona enums and LinkedIn-only account type
- [x] Add Brand Score component model
- [x] Seed persona templates and content toolkit examples
### Phase 2: Profile Ingest And Audit
- [x] Implement LinkedIn import endpoint with manual payload fallback
- [x] Build profile audit scoring
- [x] Persist profile recommendations
- [x] Add tests for audit output
### Phase 3: Brand Score And Persona Strategy
- [x] Compute Brand Score v1 from available LinkedIn metrics
- [x] Map pathway context to one of the personas
- [x] Persist strategy settings and posting cadence
- [x] Emit Brand Score update event on meaningful changes
### Phase 4: Content Calendar And Drafts
- [x] Generate a 2-week content calendar
- [x] Enforce 80/20 split
- [x] Generate LinkedIn draft content
- [x] Add dynamic triggers for pathway milestone and score-change events
### Phase 5: Approval And Publish Flow
- [x] Implement approval queue
- [x] Support approve/reject/regenerate
- [x] Support manual publish confirmation
- [x] Record posting state transitions
### Phase 6: Dashboard And Hardening
- [x] Build dashboard endpoint with score trend and queue summary
- [x] Add happy path tests
- [x] Document deferred multi-platform and enterprise work
## Review Checklist
- [x] Service works without live LinkedIn OAuth
- [x] LinkedIn is the only live platform in v1
- [x] Brand Score does not depend on unavailable metrics
- [x] Approval queue blocks publishing until approval
- [x] Multi-platform and enterprise features stay deferred
- [x] Dashboard exposes useful state to Pathways and users
## Suggested File Layout
- `app/api/v1/accounts.py`
- `app/api/v1/content.py`
- `app/api/v1/dashboard.py`
- `app/services/brand_score.py`
- `app/services/persona_strategy.py`
- `app/services/content_calendar.py`
- `tests/test_social_branding_flow.py`
## Commands
```bash
cp .env.example .env
uv sync --extra dev
uv run pytest
docker compose up --build
```
## Done Definition
This service is done for the overnight run when a seeded user can:
1. import a LinkedIn profile snapshot
2. receive an audit and Brand Score
3. get a persona-based 2-week content calendar
4. review generated drafts in an approval queue
5. approve and mark a post as published
6. see score and activity reflected in a dashboard response

View File

@@ -0,0 +1,161 @@
# PRD additions we can implement next (excluding posting + new platforms)
Date: 2026-03-26
Source: `docs/PRD.md`
Exclusions: **(1)** anything that actually posts/executes content to platforms, **(2)** adding/supporting new platforms beyond the current LinkedIn-first implementation.
This doc lists **only** items explicitly described in the PRD that are either missing or only partially implemented in the current codebase.
---
## 1) Brand Score: full PRD component model + breakdown
**PRD section:** “2.1 Brand Score Components”, “2.2 Brand Score → RQx Integration”
Add the remaining Brand Score components as first-class computed fields (and store their breakdown), not just a profile audit-derived score:
- **Content Consistency (20%)**: consistency of posting frequency + tone consistency over a rolling window.
- **Audience Growth (15%)**: follower/connection growth rate over a 30-day rolling window.
- **Engagement Rate (15%)**: likes/comments/shares/saves as % of reach.
- **Recruiter Visibility (15%)**: profile appearance rate in recruiter/talent searches (LinkedIn primary).
- **Content Quality (10%)**: AI-assessed relevance/originality/alignment to persona framework.
- **Cross-Platform Consistency (5%)**: messaging/voice alignment across connected platforms (schema-ready; compute from available platforms only).
Also implement PRD-required outputs:
- Brand Score trend line (history storage + API response)
- “objective, measurable signals” explanations per component
---
## 2) Brand Score → RQx mapping + events
**PRD section:** “2.2 Brand Score → RQx Integration”
Implement/confirm the PRD mapping and event rules end-to-end:
- Compute & store **RQx contribution** as: `Brand Score × 0.4`
- Ensure recalculation runs **after every platform sync** (LinkedIn daily in PRD)
- Emit update when Brand Score changes by **5+ points** (PRD) and include before/after + metadata
- Persist and expose Brand Score history for the dashboard (trendline)
---
## 3) LinkedIn profile rewrite variants + user selection
**PRD section:** “5.1 LinkedIn → Profile Rewrite”
Generate PRD-specified rewrite options for user approval/selection:
- Headline: **3 variants**
- About section: optimized version(s)
- Experience bullet points (per role)
- Skills list mapped to Q-Scores + target JD keywords
This is PRD “Generate → Approve” behavior and does **not** require posting.
---
## 4) Recruiter visibility: keyword gap analysis + injection recommendations
**PRD section:** “5.1 LinkedIn → Recruiter Visibility”; Brand Score component “Recruiter Visibility”
Add the PRD keyword gap workflow:
- Identify missing recruiter-search terms for the target role
- Provide **where to inject** them (headline/about/experience/skills) and generate suggested rewrites
- Score each section 0100 and benchmark vs target role (PRD says “benchmark against top 10% in same role”)
---
## 5) Connection strategy drafts (no sending)
**PRD section:** “5.1 LinkedIn → Connection Strategy”
Implement the PRD deliverables without executing any connection actions:
- Identify target connections (target companies, peers, hiring managers)
- Draft **personalized connection request notes** for approval
- Track acceptance-rate analytics inputs (data collection method TBD per PRD)
---
## 6) Engagement response drafts (approval-gated, no automation)
**PRD sections:** Pillar “Engagement”; “4.2 Dynamic Content → Engagement response drafts”; “5.1 LinkedIn → Engagement Automation”
Add draft generation (only) for:
- Replies to comments on user posts
- Comments on posts from target connections/industry leaders
All actions remain **draft-only** and **approval-gated**.
---
## 7) Content calendar generation rules enforcement (planning-side only)
**PRD section:** “4.3 Content Calendar Generation Rules”
Enforce the PRD rules in calendar generation + approval queue mechanics:
- **Rule 1: Frequency enforcement** + reminders 48hrs in advance if slots arent approved
- **Rule 2: Platform sequencing** (formatting/unique versions) — for now enforce at least “no naive duplication” within LinkedIn content types/templates
- **Rule 3: 80/20 split** maintained over a rolling 2-week window
- **Rule 4: No auto-post without approval** (keep; optionally support PRD “auto-approve mode” as opt-in *approval behavior*, not posting)
- **Rule 5: Tone lock** after first 2 weeks unless user resets
- **Rule 6: Sensitive topic filter**: risky content is flagged and not queued for approval
These changes are about **planning, generation, and approvals**, not posting.
---
## 8) Tracking + weekly analytics dashboard (read-only metrics)
**PRD section:** “1.1 The Automation Loop → Track”; “5.1 LinkedIn → Analytics Tracked”
Implement the PRD “Track” layer to collect, store, and display (no posting needed):
- Profile views (7-day, 30-day)
- Search appearances
- Post impressions
- Engagement rate per post
- Connection acceptance rate
- Follower growth
Add PRD-required presentation:
- Weekly analytics dashboard
- Brand Score trend line
---
## 9) Data requirements layer (LinkedIn) — collection mechanism + constraints doc
**PRD section:** “6. Data Requirements — Individual”
PRD leaves the method “TBD by technical team” but requires confirmation of availability. Add the engineering artifacts the PRD calls for:
- Document collection mechanism (API vs scraping vs user export)
- Document legal/rate-limit constraints
- Confirm which fields in PRD can/cant be reliably collected now
- Implement a stable “profile snapshot + metrics snapshot” storage model for the required data
---
## 10) Persona switching support
**PRD section:** “3. Six end-goal personas — content framework”
PRD states users can switch personas as goals evolve. Implement:
- Changing persona for a profile
- Persist persona choice and regenerate future calendar/drafts under the new persona
- Keep approval queue consistent (what happens to existing suggested/scheduled items)
---
## Notes / alignment with current repo state
- The repo already has foundations for: LinkedIn profile ingest, audit, deterministic calendar/draft generation, approval workflow, Brand Score v1, and dashboard state.
- The items above are the next PRD-scoped additions that dont require new platforms or posting.

File diff suppressed because it is too large Load Diff

Binary file not shown.

View File

@@ -0,0 +1,251 @@
**GrowQR**
**Interview & Roleplay Services**
Candidate Performance Rubrics
Universal Scoring \+ Archetype Modifiers • v1.0 • March 2026
**1\. Purpose & Scope**
This document defines how a candidate's performance is evaluated across the Interview and Roleplay services on GrowQR. It is used by:
* AI analysis engine — to assign per-metric scores and compute the overall weighted score
* Platform recommendation logic — to generate personalised improvement guidance
* Coaches and pathway managers — to review session results and decide progression
* Candidates — to understand exactly what is expected at each performance level
**1.1 Handling Behavioural Questions — STAR Framework**
Behavioural questions appear across all 4 interview types. When the AI detects a behavioural question (typically starting with 'Tell me about a time when…', 'Describe a situation where…', or 'Give me an example of…'), it evaluates the candidate's response using the STAR framework. STAR output feeds into Language scoring, P-S-I completeness, and Bluff Detection — it is not a separate metric.
| STAR Framework — Handling Instruction for Behavioural Questions • Applies to all 4 interview types | | | |
| ----- | :---- | :---- | :---- |
| When a behavioural question is asked (e.g. 'Tell me about a time when…'), the AI evaluates structure using the STAR framework. STAR is not a separate scored metric — it feeds directly into Language (structure and articulation), Content Quality / P-S-I (completeness and impact framing), and Bluff Detection (specificity and ownership of the Action). The table below defines what the AI looks for at each component and how it connects to scoring. | | | |
| **Component** | **Definition** | **What the AI looks for** | **Scoring impact** |
| **S** **Situation** | Set the context. What was the background or environment at the time? | Does the candidate establish a clear, specific scenario rather than a generic one? Is the context relevant to the question asked? Is the situation described concisely — setting the scene without over-explaining? | Missing or vague Situation scores lower on Language (structure) and Content Quality. A candidate who jumps straight to action without context is flagged under Technical Flow. |
| **T** **Task** | What was your specific responsibility or challenge within that situation? | Does the candidate distinguish their individual role from the team's role? Is the task framed as their personal ownership — not just 'we had a problem'? Is the complexity or stakes of the task communicated? | Candidates who blur Situation and Task together, or who cannot articulate their specific ownership, score lower on Language and trigger Resume vs Answer Mismatch checks if the claimed seniority is inconsistent. |
| **A** **Action** | What specific steps did you personally take to address the task? | Are the actions described in first person ('I did X') not team actions ('we did X')? Are the steps specific and sequential — not vague ('I worked hard on it')? Does the action demonstrate the competency being assessed by the question? | This is the highest-weight STAR component in the AI's evaluation. Vague action with no personal specificity is the primary Bluff Detection trigger. Missing or generic actions pull Language and Voice scores down. |
| **R** **Result** | What was the measurable outcome or impact? Quantify where possible. | Is the result quantified — speed, accuracy, cost, users, revenue, time saved? Does the candidate own the result or deflect it to the team or circumstances? Is the result proportionate to the action described — not over-claimed? | Result maps directly to the Impact component of P-S-I. Missing Result \= lower Language score. Quantified Result with business framing \= Score 45 indicator. Over-claimed Result without supporting Action \= Bluff Detection flag. |
**2\. Pass / Fail Logic**
The following rules govern whether a candidate session is marked as Passed, Progressing, or Not Passed.
| Rule | Detail |
| :---- | :---- |
| **Overall Pass Threshold** | Weighted overall score ≥ 60% across all active metrics. Scores below 60% \= session not passed. |
| **Blocking Floor** | Any single metric scoring 1 (Needs Major Work) is a blocking flag — session cannot be marked Passed regardless of overall weighted score. Candidate must remediate and re-attempt. |
| **Certificate Eligibility** | Roleplay only: certificate issued when weighted overall score ≥ 70% with no metric scoring below 2\. |
| **Archetype Override** | Archetype modifiers (Section 4\) may raise per-metric pass thresholds above the universal floor. The universal 60% weighted threshold still applies; archetype modifiers add per-metric minimum requirements on top. |
| **Historical Progression** | A candidate who scores below 60% but shows a positive trend across ≥3 sessions may be flagged for Progressing status rather than a hard fail — at coach or pathway manager discretion. |
**3\. Scoring Scale Reference**
All metrics use a 15 integer scale. Each score maps to a performance level with defined meaning and action.
| Score | Level | Meaning for Candidate | Action Required |
| ----- | :---- | :---- | :---- |
| **1** | **Needs Major Work** | Fundamental gaps; performance significantly below minimum standard | Immediate targeted coaching or course; re-assess before progressing |
| **2** | **Developing** | Below standard; clear gaps but early-stage development visible | Structured practice plan required; progress to next stage only with support |
| **3** | **Approaching** | Close to standard; minor but consistent gaps remain | Specific gap remediation; eligible to progress with a development note |
| **4** | **Proficient** | Meets standard; demonstrates expected professional competency | Ready to progress; log as strength if consistent across sessions |
| **5** | **Exemplary** | Exceeds standard; stands out as a strong performer in this area | Highlight as differentiator; recommend showcase or advanced challenge |
**4\. Interview Service — Universal Candidate Rubrics**
*The Interview Service uses 8 scored metrics. Weights shown are the universal defaults — Voice 17%, Technical Quality 3%, Time Intelligence 5% (new in v2.0). Archetype-adjusted weights are in Section 7\.*
| INTERVIEW SERVICE — 8 Metrics • Universal Weights • Total \= 100% | | | |
| :---- | ----- | :---- | :---- |
| **Metric & Weight** | **Score / Level** | **What the candidate demonstrates** | **Red-flag behaviours to log** |
| **Intro (Opening)** *Weight: 10%* | **1** **Needs Major Work** | Fails to introduce themselves No name, role, or context offered | Silence or confusion at start Reads from notes word-for-word Introduces irrelevant personal information |
| | **2** **Developing** | States name but omits professional context Introduction is present but very brief with no narrative thread | Tone is flat or apologetic from the first sentence Cannot summarise what they do in one sentence |
| | **3** **Approaching** | Introduces name, current role, and general background Shows basic confidence in delivery Sets a broadly relevant context for the interview | Introduction runs over 90 seconds without prompting Jumps into full career history rather than a focused opener |
| | **4** **Proficient** | Clear, structured opener: name, role, key expertise, and why they are here Confident tone and natural pacing Creates a positive first impression within 4560 seconds | No notable issues; minor polish on specificity |
| | **5** **Exemplary** | Compelling 3045 second opener that frames their value proposition Hooks the interviewer with a specific achievement or differentiator Tone is warm, confident, and conversational — feels unrehearsed yet polished | None expected at this level |
| **Facial Expression** *Weight: 20%* | **1** **Needs Major Work** | Expressionless throughout the session No eye contact with camera | Visible stress or anxiety (tense jaw, furrowed brow sustained throughout) Looking away from screen persistently Visible eye-rolling or disengaged expression |
| | **2** **Developing** | Occasional eye contact but inconsistent Expression shifts slightly with question changes but lacks warmth | Expression incongruent with content (smiling while describing failure) Stares blankly at screen for extended periods |
| | **3** **Approaching** | Maintains moderate eye contact through most responses Expression is broadly appropriate to conversation tone Occasional natural smile present | Eye contact breaks frequently during difficult questions Expression noticeably tightens under pressure |
| | **4** **Proficient** | Consistent eye contact with camera throughout Expressions are natural and match the tone of each response Smile is appropriate and genuine when context allows Emotional state reads as calm and engaged | Slight over-correction (forced smile when inappropriate) |
| | **5** **Exemplary** | Dynamic, expressive face that reinforces key points Eye contact is commanding without being uncomfortable Authentic emotional range — empathy, enthusiasm, seriousness deployed appropriately Expressions actively build rapport across the session | None expected at this level |
| **Body Language** *Weight: 20%* | **1** **Needs Major Work** | Slouched or collapsed posture throughout Fidgeting continuously (touching face, tapping, swivelling) | Head in hands or hunched over Turning away from camera repeatedly Arms crossed and body closed for full session |
| | **2** **Developing** | Posture is mostly upright but collapses under pressure Gestures are present but erratic or distracting | Excessive self-touching (hair, face, collar) Visible restlessness in seat Gestures cut off at camera frame — no visible impact |
| | **3** **Approaching** | Upright seated posture maintained for majority of session Gestures are present and broadly controlled Minimal fidgeting observed | Posture deteriorates noticeably in the second half Gestures repeat without purpose (filler gestures) |
| | **4** **Proficient** | Consistently upright and open posture throughout Gestures are purposeful and reinforce key points No distracting movement observed Professionalism reads clearly in physical presence | Occasional single gesture that is distracting — does not recur |
| | **5** **Exemplary** | Posture conveys authority and ease simultaneously Gestures are varied, well-timed, and add meaning to speech Physical stillness during listening communicates attentiveness Overall physical presence would stand out positively in a panel interview | None expected at this level |
| **Language** *Weight: 15%* *Two sub-criteria embedded across all 4 interview types: (1) P-S-I — when explaining work or projects, responses should be structured as Problem → Solution → Impact. (2) Technical Flow — when explaining domain concepts, ideas should connect logically in sequence (e.g. Tokenization → Embeddings → Attention → Inference). Technical Flow directly strengthens Bluff Detection: a candidate who cannot chain concepts is flagged regardless of confident tone.* | **1** **Needs Major Work** | Frequent grammatical errors that impede understanding Vocabulary is too limited to articulate responses clearly P-S-I: No structure evident — response is a stream of disconnected statements with no identifiable problem, solution, or impact Technical Flow: Concepts mentioned in isolation with no logical connection between them — e.g. names LLM and Embeddings but cannot explain how one leads to the other | Incomplete sentences left hanging Cannot find words and falls silent mid-thought regularly Uses slang or highly informal register throughout Cannot describe what problem their work solved Uses correct technical keywords but cannot sequence them — strong bluff signal |
| | **2** **Developing** | Basic grammatical structure mostly present Vocabulary is functional but lacks range for professional context P-S-I: One element present (usually Solution only) — candidate describes what they did but not why or what changed Technical Flow: One or two concept links are made correctly but chain breaks down or reverses midway | Frequent repetition of same limited phrases Sentence structures are consistently simple and short Technical terms used incorrectly or avoided entirely Describes actions with no context or outcome Concept chain stalls after the first step — cannot proceed without prompting |
| | **3** **Approaching** | Clear sentence structure throughout Vocabulary is appropriate for the level and role Responses are articulate and understandable with minimal re-listening needed P-S-I: Two of three elements present — typically Problem \+ Solution but Impact is vague or absent Technical Flow: Concept chain is mostly correct — candidate sequences 34 ideas logically but loses precision or depth at the final step | Occasional grammatical slip under pressure Some over-reliance on a limited phrase set Impact described but not quantified — 'it went well' without specifics Concept chain correct but shallow — links are made without explaining why each step follows |
| | **4** **Proficient** | Varied vocabulary deployed naturally and accurately Grammar is consistently correct including under pressure Uses precise language — avoids vague filler phrases ('kind of', 'sort of') Sentence structure reflects logical thinking P-S-I: All three elements present and clearly sequenced — Problem is contextualised, Solution includes their specific role, Impact is concrete Technical Flow: Full concept chain delivered accurately and in correct sequence — each step explained and linked to the next | Rare slip on technical terminology Impact is stated but not quantified numerically Concept chain is complete but one link is explained less clearly than the others |
| | **5** **Exemplary** | Sophisticated, professional vocabulary used with confidence Language is persuasive and well-constructed under all conditions Candidate adapts register to question type (technical vs. behavioural) Demonstrates command of industry-relevant language naturally P-S-I: All three elements delivered with precision — Impact is quantified (speed, accuracy, cost, users), Solution distinguishes their individual contribution from team effort, Problem is framed in business terms not just technical terms Technical Flow: Concept chain is complete, correctly sequenced, and delivered with depth at every link — candidate can also explain why the sequence matters, not just what it is | None expected at this level |
| **Voice** *Weight: 17%* | **1** **Needs Major Work** | Volume too low to hear clearly OR monotone throughout Pace is either so fast responses blur or so slow they lose the thread | 10+ filler words per minute Vocal tremor throughout suggesting extreme anxiety Mumbling that requires repeated listening |
| | **2** **Developing** | Volume is audible but flat with no tonal variation Pace fluctuates noticeably but does not break comprehension | 69 filler words per minute Upward inflection on statements (sounds like questions) Breath sounds audible and distracting |
| | **3** **Approaching** | Volume is consistent and clear Pace is broadly controlled — slows for key points occasionally Tone shifts with question topic Filler word count: 35 per minute | Filler count increases under pressure Monotone returns on longer answers |
| | **4** **Proficient** | Clear, confident vocal delivery throughout Tone, pace, and volume vary purposefully across the session Filler word count: 12 per minute or fewer Silence is used effectively before complex answers | Occasional filler on transition between topics |
| | **5** **Exemplary** | Voice is a clear communication asset — engaging and authoritative Pace modulated precisely: slower for complex points, energised for enthusiasm Zero or near-zero filler words throughout the full session Strategic use of pause creates emphasis and demonstrates composure | None expected at this level |
| **Outro (Closing)** *Weight: 10%* | **1** **Needs Major Work** | Session ends without a closing statement Candidate simply stops talking with no wrap-up | Abrupt 'I think that's it' or equivalent No questions asked of the interviewer when offered Final impression is confusion or disengagement |
| | **2** **Developing** | A brief closing exists but it is generic ('Thanks for having me') One question asked but it is low-effort (e.g., 'What's the salary?') | Closing contradicts earlier answers Question to interviewer reveals no research or interest in the role |
| | **3** **Approaching** | Clear closing statement that re-states interest in the role One or two relevant questions asked Ends on a broadly positive note | Closing is formulaic but inoffensive Questions are predictable and do not differentiate the candidate |
| | **4** **Proficient** | Confident closing that references something specific from the interview 23 thoughtful questions that show genuine role/company knowledge Candidate reaffirms their fit in a natural, non-scripted way Final impression is positive and memorable | Closing is slightly over-rehearsed — minor authenticity gap |
| | **5** **Exemplary** | Closing creates a lasting impression: references a specific interview moment and ties it to their value Questions are incisive and demonstrate genuine strategic thinking about the role Candidate controls the final narrative — ends on their terms Interviewer's last impression is that this person is ready | None expected at this level |
| **Technical Quality** *Weight: 3%* | **1** **Needs Major Work** | Setup is so poor it undermines the interview (dark room, no audio, chaotic background) | Camera is not on face — candidate not visible Audio is inaudible Background is deeply unprofessional (others visible, noise throughout) |
| | **2** **Developing** | Setup is substandard but interview can proceed One or two technical issues that distract but do not block evaluation | Lighting casts heavy shadows on face Background has moving distractions Audio has persistent background noise |
| | **3** **Approaching** | Acceptable setup — lighting is adequate, framing is centred, background is neutral Audio is clear with minor occasional noise | Framing is slightly off-centre Lighting is functional but not flattering |
| | **4** **Proficient** | Well-lit face, centred framing, clean or professional background Audio is consistently clear throughout Setup communicates that the candidate took the interview seriously | Minor background element that is noticeable but not distracting |
| | **5** **Exemplary** | Setup is interview-ready and projects professionalism Lighting, framing, background, and audio are all at a high standard Setup actively contributes to a positive overall impression | None expected at this level |
| **Time Intelligence** *Weight: 5%* *Measures cognitive response patterns under pressure — not just speed, but the quality of thinking behind the timing. Healthy pauses score positively; blank freezes and overthinking loops score negatively.* | **1** **Needs Major Work** | Response latency is so long (\>20s of silence) that the interview is disrupted Candidate freezes and cannot recover without interviewer prompting on most questions | Blank freezes exceeding 20 seconds on standard questions Consistently restates the question back as a stalling tactic Overthinking loop visible — candidate goes in circles without committing to an answer Delay patterns cluster on basic questions, not just difficult ones |
| | **2** **Developing** | Responses begin but with significant latency (1020s) on most questions Thinking pauses are present but feel like blank hesitation rather than active processing | Excessive hedging that prevents any substantive answer from forming Delay patterns cluster on predictable topic areas revealing consistent knowledge gaps Candidate regularly restates or rephrases the question before answering |
| | **3** **Approaching** | Response latency is within acceptable range (38s) for most questions Pauses feel like genuine thinking rather than blank freezes Performance degrades on harder questions but candidate recovers and delivers an answer Delay patterns are limited to clearly complex or unfamiliar topics | Occasional overthinking loop on one or two questions Latency increases noticeably on topic-specific questions — possible gap signal |
| | **4** **Proficient** | Response latency is consistently appropriate — short pause before complex answers, faster on familiar topics Thinking pauses are deliberate and purposeful; candidate uses them to structure their answer Performance under harder questions is composed — slight increase in latency but no freezes No overthinking loops observed; candidate commits to an answer direction and follows through | One topic area shows marginally longer delay — flag for follow-up but not penalised |
| | **5** **Exemplary** | Response timing is a communication strength — pauses are used strategically for emphasis Complex questions receive a brief, deliberate pause followed by a structured, confident answer No blank freezes across the full session including on curveball questions Delay patterns show no topic-specific clustering — consistent across all question types Candidate demonstrates real-time adaptability: new topics handled without latency spike | None expected at this level |
**5\. Consistency & Truth Check — Integrity Flags**
This dimension is unweighted and does not affect the candidate's scored rubric. The AI raises flags in each of the three categories below based on cross-referencing resume/LinkedIn data against session responses. Recruiter and coach see full flag detail. Candidate sees a summary 'Consistency Check' result only.
| ⚑ Consistency & Truth Check — Unweighted integrity flags — raised by AI for recruiter/coach review. Candidate sees summary result only. | | |
| :---- | :---- | :---- |
| **Flag Type** | **What AI Monitors** | **Flag Output — what recruiter/coach sees** |
| **Resume vs Answer Mismatch** *AI cross-references skills, experience, and achievements claimed on the candidate's uploaded resume or LinkedIn profile against what they demonstrate and state verbally during the session.* | Skill listed on resume cannot be explained or demonstrated when probed — e.g., claims Python proficiency but cannot answer basic syntax questions Experience duration or seniority level claimed on resume inconsistent with depth of answers given Specific achievement or project mentioned on resume but candidate cannot provide detail when asked Claimed certifications or qualifications not supported by demonstrated knowledge | Flag raised with: specific resume claim, specific interview moment, mismatch severity (Minor / Moderate / Significant) |
| **Contradiction Tracking** *AI tracks statements made across the full session and flags direct contradictions — e.g., claiming a strength in one answer that is contradicted by a specific weakness admission later.* | Candidate states conflicting information about the same event, project, or role in two different answers Team size, timeline, or scope of a project described differently in separate answers Candidate claims credit for a decision in one answer and attributes it to someone else in a later answer Technical approach described differently across two answers on the same topic | Flag raised with: answer 1 timestamp, answer 2 timestamp, verbatim conflict summary |
| **Bluff Detection** *AI identifies responses that sound confident but are technically vague, logically circular, or fall apart under follow-up questioning.* | Confident tone but answer contains no substantive technical or factual content — sounds plausible but says nothing specific Candidate uses correct terminology but cannot explain what the term means when asked to elaborate Answer evades the question by pivoting to a related but different topic Response contradicts itself internally within the same answer Follow-up question on the same topic reveals the initial answer was surface-level — depth was not present | Flag raised with: question asked, answer summary, specific evasion or gap identified |
**6\. Roleplay Service — Universal Candidate Rubrics**
*The Roleplay Service uses 5 scored metrics. Weights shown are universal defaults. P-S-I framework is embedded in Content Quality (new in v2.0). Archetype-adjusted weights and minimum scores are in Section 7\.*
| ROLEPLAY SERVICE — 5 Metrics • Universal Weights • Total \= 100% | | | |
| :---- | ----- | :---- | :---- |
| **Metric & Weight** | **Score / Level** | **What the candidate demonstrates** | **Red-flag behaviours to log** |
| **Voice** *Weight: 35%* | **1** **Needs Major Work** | Inaudible or monotone throughout the scenario Pace makes content impossible to follow | 10+ filler words per minute Candidate cannot sustain voice for the scenario duration Tone is entirely inappropriate to the scenario context |
| | **2** **Developing** | Basic vocal delivery — audible but flat Tone shows minimal variation across the scenario | 69 filler words per minute Pace rushes through critical scenario moments Vocal confidence drops sharply when challenged by the AI persona |
| | **3** **Approaching** | Clear vocal delivery throughout most of the scenario Tone adapts to scenario context (formal vs. collaborative) Filler count: 35 per minute Pace is broadly appropriate | Filler words cluster at scenario transitions Tone does not fully match the scenario type |
| | **4** **Proficient** | Confident, clear, scenario-appropriate voice throughout Filler count: 12 per minute Pace and tone actively serve the scenario narrative Candidate sounds credible and competent in the scenario role | Occasional filler on complex turns |
| | **5** **Exemplary** | Voice is a scenario asset — conveys authority, warmth, or precision as required Near-zero filler words throughout Pace and emphasis deployed with intent Voice alone communicates engagement and professional confidence | None expected at this level |
| **Facial Expression** *Weight: 25%* | **1** **Needs Major Work** | Expressionless or visibly stressed throughout No eye contact with camera | Expression is incongruent with scenario tone throughout Candidate appears disconnected from the scenario entirely |
| | **2** **Developing** | Minimal expression — present but not engaged Eye contact inconsistent | Smile inappropriate for the scenario type Stress visible on face during most exchanges with the AI persona |
| | **3** **Approaching** | Appropriate expressions for the scenario context Moderate eye contact maintained through most turns Shows engagement when the AI persona challenges them | Expression drops in intensity during longer monologue turns |
| | **4** **Proficient** | Expressions actively reinforce the scenario role Consistent, natural eye contact that conveys presence Emotional range is scenario-appropriate — not over-performed | Rare mismatch between expression and content |
| | **5** **Exemplary** | Facial performance matches the professional situation being simulated Eye contact builds trust and engagement with the AI persona Dynamic expression range — enthusiasm, empathy, calm deployed at the right moments Would stand out positively in a real-world version of the scenario | None expected at this level |
| **Body Language** *Weight: 20%* | **1** **Needs Major Work** | Posture is collapsed or turned away from camera throughout | Fidgeting is constant and distracting Body language contradicts verbal message (closed posture while claiming confidence) Movement is so frequent that analysis is compromised |
| | **2** **Developing** | Posture is mostly upright but falls under pressure Gestures are present but not controlled | Physical restlessness increases as scenario progresses Closed arm posture dominant |
| | **3** **Approaching** | Upright posture for most of the scenario Gestures are present and do not distract Physical presence is broadly appropriate to the scenario context | Posture deteriorates noticeably after 10 minutes |
| | **4** **Proficient** | Open, upright posture throughout Gestures are purposeful and add to the communication Physical stillness when listening signals attentiveness Professionalism reads clearly in physical presentation | Single distracting gesture that does not recur |
| | **5** **Exemplary** | Physical presence is a communication strength Body language is aligned with voice and expression throughout Scenario-appropriate authority or approachability projected through physicality Candidate would be compelling in-person based on what is observable on camera | None expected at this level |
| **Technical Quality** *Weight: 10%* | **1** **Needs Major Work** | Setup prevents meaningful evaluation (no light, no audio, disruptive background) | Camera not showing face Background has people or high noise throughout Audio is inaudible |
| | **2** **Developing** | Substandard but session can continue One persistent technical issue throughout | Lighting obscures facial analysis Background noise triggers at least once per minute |
| | **3** **Approaching** | Acceptable setup across all four dimensions Minor issues do not impact analysis | Framing is off-centre for most of the session |
| | **4** **Proficient** | Well-lit, centred, clean background, clear audio throughout Setup signals preparation and professionalism | Single brief audio or background interruption |
| | **5** **Exemplary** | Setup is a professional asset — all four dimensions at high standard Audio, light, framing, and background all contribute to a polished impression | None expected at this level |
| **Content Quality** *Weight: 10%* *P-S-I sub-criterion: when explaining scenario context, decisions, or past work, candidates should structure responses as Problem → Solution → Impact. Scores reflect both content completeness and narrative structure.* | **1** **Needs Major Work** | Responses are irrelevant to the scenario or entirely off-topic Cannot complete the scenario task P-S-I: No structure — response has no identifiable Problem, Solution, or Impact framing | Candidate abandons the scenario premise mid-session Responses are factually wrong in a way that would fail in a real situation No attempt to meet the scenario objective |
| | **2** **Developing** | Responses are on-topic but shallow and incomplete Scenario task is partially addressed only P-S-I: Solution only — candidate describes what they did or would do but provides no problem context and no impact outcome | Key scenario objectives are left unaddressed Responses rely on generic statements rather than scenario-specific reasoning Cannot articulate what success looks like in the scenario |
| | **3** **Approaching** | Responses are relevant and mostly complete Core scenario objective is addressed Accuracy is broadly acceptable P-S-I: Problem \+ Solution present — scenario challenge acknowledged and response is relevant, but Impact is absent or vague | One or two scenario objectives missed or underaddressed Outcome described loosely without measurable framing |
| | **4** **Proficient** | All scenario objectives addressed accurately and completely Responses are relevant, structured, and demonstrate genuine understanding of the scenario context Candidate adds value beyond the minimum scenario requirement P-S-I: All three elements present — Problem is framed clearly, Solution includes specific actions taken, Impact is concrete and scenario-relevant | Minor omission in one area that does not affect overall outcome |
| | **5** **Exemplary** | Scenario is mastered — all objectives addressed with insight and precision Candidate demonstrates a level of thinking that exceeds the scenario brief Responses show domain command, strategic awareness, and situational intelligence Would achieve a strong real-world outcome in this scenario P-S-I: Exemplary structure — Problem is framed in stakeholder terms, Solution distinguishes their role from team contribution, Impact is quantified and tied to business or user outcome | None expected at this level |
**7\. Archetype Modifiers**
For each of the 5 GrowQR archetypes, the tables below define: (1) adjusted metric weights that re-prioritise what matters for that archetype, (2) per-metric minimum scores that must be reached regardless of the overall weighted average, and (3) what 'good' looks like for that archetype specifically. Time Intelligence is now included across all 5 archetypes with archetype-specific minimum scores. Cells highlighted in green indicate a higher-than-universal weight. Cells highlighted in red indicate a minimum score above the universal floor.
*⚑ Terminology note: The Pathways Booklet (source document) references 8 archetypes (The Strategist, The Executor, The Innovator, The Connector, The Specialist, The Explorer, The Builder, The Catalyst). This rubric uses the 5 locked GrowQR platform archetypes. Reconciliation of booklet language to the locked 5 is required before Pathways BRD v5 is finalised.*
**Technical Specialist**
| Technical Specialist — Depth of expertise, precision of communication, credibility under scrutiny | | | | |
| ----- | :---- | ----- | ----- | :---- |
| **Service** | **Metric** | **Adjusted Weight** | **Min Score to Pass** | **What 'Good' Looks Like for This Archetype** |
| **Interview** | **Intro** | 8% | **3** | Opener should reference domain expertise and a specific technical achievement; generic openers score lower for this archetype. |
| | **Facial Expression** | 15% | **3** | Moderate expressiveness is acceptable; assessment prioritises authenticity over performance. Forced warmth scores lower than composed neutrality. |
| | **Body Language** | 15% | **3** | Composed stillness is valued over expressive gestures. Fidgeting during technical explanations is weighted more heavily as it signals uncertainty. |
| | **Language** | **22%** | **4** | Precise technical vocabulary is a core requirement. Must score ≥4 — inability to articulate technical concepts clearly is a critical gap for this archetype. |
| | **Voice** | 15% | **3** | Clarity and pace matter more than charisma. A measured, deliberate pace during technical explanations is a strength. |
| | **Outro** | 8% | **3** | Questions asked should reflect technical curiosity (stack, architecture, engineering culture). Generic questions score lower. |
| | **Technical Quality** | **12%** | **3** | Setup quality is weighted higher — screen share functionality must be tested as part of this archetype's typical coding interview scenarios. |
| | **Time Intelligence** | 5% | **4** | Deliberate, structured pauses before technical answers are a positive signal. However, blank freezes on fundamental domain questions are a critical gap — must score ≥4. |
| | **Learning Ability** | — | **3** | Additional passing criterion — unweighted but blocking. When the AI persona gives a hint or correction mid-session, the candidate must demonstrate measurable improvement in the very next relevant answer. Score ≥3 required: candidate grasps the hint and applies it. Score 12 \= blocking flag regardless of overall weighted score. |
| **Roleplay** | **Voice** | 30% | **3** | Precision over charisma. Clarity during technical explanation turns is the key voice indicator. |
| | **Facial Expression** | 20% | **3** | Engagement is important but over-performance is penalised. Composed focus is a strength. |
| | **Body Language** | 18% | **3** | Stillness during technical delivery is a positive indicator, not a deficit. |
| | **Technical Quality** | **12%** | **4** | Higher weight and minimum for this archetype — professional setup is expected; IDEs and coding demo screen shares must function correctly. |
| | **Content Quality** | **20%** | **4** | Content accuracy is critical. Technical errors in scenario responses are blocking for this archetype. Must score ≥4. |
**Strategic Leader**
| Strategic Leader — Executive presence, structured thinking, command of room and narrative | | | | |
| ----- | :---- | ----- | ----- | :---- |
| **Service** | **Metric** | **Adjusted Weight** | **Min Score to Pass** | **What 'Good' Looks Like for This Archetype** |
| **Interview** | **Intro** | **12%** | **4** | Opening must establish leadership narrative and strategic framing within 45 seconds. Must score ≥4 — a weak opener is disqualifying for this archetype. |
| | **Facial Expression** | **22%** | **4** | Executive presence requires strong expressive engagement. Eye contact must project authority and warmth simultaneously. Must score ≥4. |
| | **Body Language** | **22%** | **4** | Posture and gesture are leadership signals. Open, upright, deliberate physicality is a core requirement. Must score ≥4. |
| | **Language** | 18% | **4** | Structured, precise language with strategic vocabulary. Candidate should frame responses in terms of impact, outcomes, and decisions. |
| | **Voice** | 15% | **4** | Tone of authority is expected. Pace should be deliberate. Filler words are weighted more heavily as they undermine executive presence. |
| | **Outro** | 6% | **3** | Closing should be decisive and forward-looking. Questions to interviewer should reflect strategic thinking about the organisation. |
| | **Technical Quality** | 2% | **2** | Minimal weight. Basic acceptable setup is sufficient. Setup quality is not a differentiator for this archetype. |
| | **Time Intelligence** | 3% | **5** | Deliberate, composed pacing is a core leadership signal. Any hesitation or overthinking loop is penalised heavily — must score ≥5 to confirm executive-level command of timing. |
| **Roleplay** | **Voice** | **38%** | **4** | Voice is the primary leadership instrument. Tone of authority, deliberate pacing, and near-zero filler are all required at ≥4. |
| | **Facial Expression** | **28%** | **4** | Commanding presence through expression is a core requirement. Must score ≥4. |
| | **Body Language** | **24%** | **4** | Physical authority is non-negotiable for this archetype. Open, stable, deliberate physicality throughout scenario. Must score ≥4. |
| | **Technical Quality** | 4% | **2** | Low weight. Acceptable setup is sufficient. |
| | **Content Quality** | 6% | **3** | Content should reflect strategic framing — responses framed around decisions, outcomes, and stakeholder impact score higher. |
**Creative Innovator**
| Creative Innovator — Original thinking, enthusiasm, ability to sell ideas and inspire curiosity | | | | |
| ----- | :---- | ----- | ----- | :---- |
| **Service** | **Metric** | **Adjusted Weight** | **Min Score to Pass** | **What 'Good' Looks Like for This Archetype** |
| **Interview** | **Intro** | **12%** | **4** | Opening should establish a distinctive personal narrative or creative differentiator. Generic openers score much lower for this archetype. Must score ≥4. |
| | **Facial Expression** | **22%** | **4** | Enthusiasm and genuine emotional engagement are core. Expressiveness is a strength, not a risk. Must score ≥4. |
| | **Body Language** | 15% | **3** | Energy and openness in physicality valued. Expressive gestures score positively — controlled stillness alone is not sufficient for this archetype. |
| | **Language** | 20% | **3** | Vivid, imaginative language is a positive indicator. Candidate should demonstrate range and the ability to explain creative concepts clearly. |
| | **Voice** | 20% | **3** | Tonal variety and genuine enthusiasm are key voice indicators. Flat delivery is penalised more than filler words for this archetype. |
| | **Outro** | 6% | **3** | Closing should leave a memorable, distinctive impression. A creative or unexpected closing question scores highly. |
| | **Technical Quality** | 2% | **2** | Low weight. Setup just needs to be functional. |
| | **Time Intelligence** | 3% | **3** | Response timing flexibility is valued for this archetype — thinking pauses score positively as signs of genuine ideation. Overthinking loops are penalised only when they prevent any answer. |
| **Roleplay** | **Voice** | 35% | **4** | Vocal energy and tonal variety are the strongest indicators. Monotone delivery scores lower than filler-heavy enthusiastic delivery for this archetype. |
| | **Facial Expression** | **30%** | **4** | Highest weight category. Expressive engagement is the primary differentiator. Must score ≥4. |
| | **Body Language** | 20% | **3** | Open, expressive physicality is valued. Gestures that reinforce creative ideas score positively. |
| | **Technical Quality** | 5% | **2** | Low weight. Basic functional setup is sufficient. |
| | **Content Quality** | 10% | **3** | Originality and unexpected angles in scenario responses score higher than technically correct but predictable answers. |
**Sales & Influence Driver**
| Sales & Influence Driver — Persuasion, rapport, emotional intelligence, energy and conviction | | | | |
| ----- | :---- | ----- | ----- | :---- |
| **Service** | **Metric** | **Adjusted Weight** | **Min Score to Pass** | **What 'Good' Looks Like for This Archetype** |
| **Interview** | **Intro** | **15%** | **4** | The opener IS the pitch. Must hook the interviewer within 30 seconds. Compelling narrative, energy, and confidence are all required. Must score ≥4. |
| | **Facial Expression** | **25%** | **4** | Warmth, rapport, and engagement through expression are essential. Genuine smile and consistent eye contact are minimum requirements. Must score ≥4. |
| | **Body Language** | **20%** | **4** | Physicality is part of the persuasion toolkit. Open, energetic, forward-leaning presence. Must score ≥4. |
| | **Language** | 15% | **3** | Persuasive, benefit-focused language scores higher. Candidate should demonstrate storytelling ability and use of social proof. |
| | **Voice** | **19%** | **4** | Voice is a primary influence tool. Energy, warmth, and confidence are all required. Flat delivery is highly penalised. Must score ≥4. |
| | **Outro** | 2% | **3** | Low weight but a strong closing is still expected — the closing is a natural home for a soft CTA or memorable statement. |
| | **Technical Quality** | 1% | **2** | Minimal weight. Functional setup is sufficient. |
| | **Time Intelligence** | 3% | **4** | Response speed signals confidence for this archetype — fast, assured responses reinforce influence. Hesitation or overthinking directly undermine persuasiveness. Must score ≥4. |
| **Roleplay** | **Voice** | **40%** | **4** | Highest weight. Voice is the primary influence vehicle. Energy, pace, and conviction are all required. Must score ≥4. |
| | **Facial Expression** | **28%** | **4** | Rapport through expression is core to this archetype's scenario performance. Must score ≥4. |
| | **Body Language** | **20%** | **4** | Persuasive physicality — open, forward, engaged. Must score ≥4. |
| | **Technical Quality** | 2% | **2** | Minimal weight. |
| | **Content Quality** | 10% | **3** | Storytelling structure and benefit framing in responses score higher than factual completeness alone. |
**Entrepreneurial Builder**
| Entrepreneurial Builder — Bias to action, resilience, vision clarity, credibility under ambiguity | | | | |
| ----- | :---- | ----- | ----- | :---- |
| **Service** | **Metric** | **Adjusted Weight** | **Min Score to Pass** | **What 'Good' Looks Like for This Archetype** |
| **Interview** | **Intro** | **12%** | **4** | Must communicate a clear vision or founding narrative. 'What they are building or have built' must be central to the opener. Must score ≥4. |
| | **Facial Expression** | 18% | **3** | Genuine conviction and authentic enthusiasm are the key expression indicators. Polished performance is valued less than authenticity. |
| | **Body Language** | 18% | **3** | Energy and presence are valued. Gestural expressiveness is a positive indicator. Some roughness at the edges is acceptable if energy is strong. |
| | **Language** | 17% | **3** | Concrete, outcome-oriented language is valued. Candidate should speak in terms of what they built, shipped, or achieved — not what they planned. |
| | **Voice** | 20% | **3** | Energy and conviction are the primary voice indicators. Polished delivery is valued less than genuine passion for the subject. |
| | **Outro** | **10%** | **4** | Higher weight. The closing should pitch the candidate's next move or vision. A builder who closes weakly scores lower — the outro should feel like a CTA. Must score ≥4. |
| | **Technical Quality** | 2% | **2** | Low weight. Functional setup is sufficient. |
| | **Time Intelligence** | 3% | **3** | Bias-to-action means faster responses are valued over extended deliberation. However, structured pauses before complex answers score positively. Blank freezes contradict the builder identity. |
| **Roleplay** | **Voice** | 32% | **3** | Authentic energy and conviction. Raw delivery with strong conviction scores higher than polished but flat. |
| | **Facial Expression** | 22% | **3** | Genuine conviction visible in expression. Authenticity weighted more than performance polish. |
| | **Body Language** | 20% | **3** | Energy and openness. Minor roughness acceptable if overall physical presence communicates engagement. |
| | **Technical Quality** | 8% | **2** | Moderate weight — builder archetypes often demo products so screen share setup quality matters more than other archetypes. |
| | **Content Quality** | **18%** | **4** | Higher weight. Scenario responses must demonstrate bias to action and outcome focus. Vague or planning-heavy responses score low. Must score ≥4. |

View File

@@ -0,0 +1,140 @@
# Interview Service Live Relay Migration
## Summary
- Keep the backend-owned Gemini Live relay websocket as the primary live interview transport. The browser does not connect to Gemini directly and does not run browser STT.
- Keep `POST /configure` and `POST /start`; after `start`, the client uses one app websocket for live transcript, prompt streaming, orchestration events, upload state, and analysis-stage updates.
- Keep per-turn audio upload, not one session-long file. Each answer records locally, commits from the live transcript on `turn.stop`, then uploads that turns blob to S3 in the background.
- Final review uses the live transcript as the grading source of truth in the normal path. Uploaded turn audio is retained for playback and voice/audio evidence, and is used for transcript recovery only when live STT fails for a specific turn.
## Key Changes
- Add `session_mode="live_audio"` as the primary live path. Keep REST `/responses` only as legacy fallback.
- For `live_audio`, enforce duration options `5`, `10`, and `15` minutes. Treat conflicting `30`-minute references in repo docs/schema as stale and update them during implementation.
- Add `WS /api/v1/interviews/{session_id}/live` in `services/interview-service/app/api/v1/interviews.py`. `POST /start` returns `live_ws_url` and the opening prompt.
- Introduce a backend live-session manager in `services/interview-service/app/services/interview_service.py` or a sibling live service that:
- opens an upstream Gemini Live session with `inputAudioTranscription` enabled
- disables automatic activity detection and drives explicit `activityStart` / `activityEnd`
- treats Gemini as transcription transport only; backend orchestration and prompt generation remain owned by the existing intelligence stack
- discards all unsolicited upstream model output instead of surfacing it to the client
- Handle Gemini connection lifetime explicitly:
- official docs say audio-only sessions are limited to 15 minutes and connection lifetime is around 10 minutes, with `GoAway` before close and optional session resumption
- v1 does not depend on Gemini session resumption because Gemini carries no authoritative orchestration state for us
- the backend rotates the upstream Gemini connection between turns whenever the connection is older than 8 minutes or after `GoAway`
- the browser websocket remains stable while the backend swaps Gemini connections underneath it
- Finalize turns safely:
- `turn.stop` sends upstream `activityEnd` immediately and stops forwarding PCM
- the backend waits on a finalization barrier before commit: no transcript growth for a short quiet window plus either upstream `serverContent.turnComplete` or a bounded timeout
- if timeout is used, persist finalization metadata on the turn
- Resolve mid-turn upstream failure without deadlock:
- if Gemini dies before the transcript can be committed, the backend emits `turn.degraded_awaiting_audio`
- the client pauses the interview UI, prioritizes that turns blob upload ahead of the normal upload queue, and does not advance to the next prompt
- the backend blocks orchestration for that turn until the degraded turn artifact is registered and legacy server transcription completes, or until recovery fails and the session is marked errored
- Keep Google TTS for interviewer audio. Emit prompt text immediately, then `prompt.audio.pending`, `prompt.audio.ready`, or `prompt.audio.failed`. The mic stays locked until audio is ready or text-only fallback is declared.
- Keep per-turn artifact upload:
- after the transcript transaction commits, the server emits `turn.committed` with `response_id`
- the client upload worker requests presign only when an item reaches the front of the queue
- normal uploads run through a strict queue with concurrency `1`
- the queue uses bounded retries, exponential backoff, and terminal `failed` state so one bad turn cannot poison later uploads
- degraded-turn recovery uploads bypass the normal queue and run in a dedicated priority lane because they are blocking orchestration
- Add upload-aware interview finish:
- `session.finish` includes `pending_upload_response_ids` and `failed_upload_response_ids`
- background review waits only for the pending ids to register or for a bounded grace window such as 30 seconds to expire
- failed ids are transcript-only immediately and do not block finish
- Fix capture and transport normalization:
- PCM extraction and `MediaRecorder` must share the same `MediaStream`
- the client must not emit `turn.start` until both the PCM path and the blob recorder report started
- the client normalizes outbound PCM to little-endian 16-bit mono at 16kHz and labels chunks as `audio/pcm;rate=16000`
- although Live can resample other input rates, standardizing client-side avoids browser hardware variability and reduces payload size
- on stop, the client sends websocket `turn.stop` immediately, but it does not enqueue the blob upload until the final `MediaRecorder` flush promise resolves
- Fix replay and spoofing:
- backend rejects `turn.start` unless `prompt_id` exactly matches the authoritative current prompt
- backend rejects reused, stale, or already-closed `client_turn_id`
- any mismatch triggers `error` plus a fresh `session.ready`
- Fix commit ordering:
- `turn.committed` is emitted only after the transcript row is fully committed to Postgres
- artifact registration cannot race ahead of transcript commit
- Keep the websocket alive after `session.finish`:
- heartbeat ping/pong continues through upload grace waiting and the full review pipeline
- the backend explicitly ends the socket with `session.closed` only after final result delivery or terminal failure
- Prevent premature tab close data loss:
- while uploads are pending, the client installs a `beforeunload` guard warning that interview audio is still syncing
- the post-interview UI shows explicit syncing progress and does not expose the final exit CTA until the queue is drained or remaining items are marked failed
## Public APIs / Protocol
- `ConfigureInterviewRequest.session_mode` gains `live_audio`.
- `ConfigureInterviewRequest.duration_minutes` is restricted to `5 | 10 | 15` for `live_audio`.
- `StartInterviewResponse` gains `live_ws_url`.
- `RegisterArtifactRequest` gains optional `response_id`.
- `InterviewArtifact` gains optional indexed `response_id`.
- Websocket client messages:
- `turn.start` with `prompt_id` and `client_turn_id`
- binary PCM audio frames for the active `client_turn_id`
- `turn.stop` with `client_turn_id`
- `session.finish` with `pending_upload_response_ids` and `failed_upload_response_ids`
- Websocket server messages:
- `session.ready` with authoritative state: `current_prompt_id`, `turn_state`, `last_committed_response_id`, pending uploads
- `transcript.partial`, `transcript.final`
- `turn.committed` with `client_turn_id`, `response_id`, transcript text, and finalization metadata
- `turn.degraded_awaiting_audio`
- `turn.timeout`
- `prompt.delta`, `prompt.final`
- `prompt.audio.pending`, `prompt.audio.ready`, `prompt.audio.failed`
- `artifact.registered`
- `analysis.queued`, `analysis.stage`, `analysis.completed`, `analysis.failed`
- `session.closed`
- `error`
- Keep existing artifact presign/upload/register endpoints. Live clients still use them, but only the upload worker or degraded-turn recovery path talks to them.
## Test Plan
- Validation:
- `live_audio` accepts `5`, `10`, `15`
- `30` is rejected in live mode
- legacy non-live modes still work
- Gemini lifetime handling:
- backend rotates upstream Gemini between turns before connection expiry
- `GoAway` causes clean pre-turn rotation without affecting the browser websocket
- browser websocket survives the full post-finish review window and closes only on `session.closed`
- Transcript finalization:
- `turn.stop` waits through the quiet-window barrier and includes trailing words
- `serverContent.turnComplete` path commits cleanly
- timeout path commits with explicit metadata instead of silent truncation
- Mid-turn failure recovery:
- upstream Gemini close during a turn emits `turn.degraded_awaiting_audio`
- degraded turn upload jumps ahead of the normal queue
- orchestration stays blocked until degraded-turn server transcription completes
- Upload queue:
- presign is requested only at queue head
- queue concurrency remains `1`
- bounded retries and backoff work
- one permanently failed upload does not block later turns
- degraded-turn priority upload bypasses normal queue safely
- Capture and blob integrity:
- `turn.start` is never sent before both PCM and blob recording are armed
- outbound PCM is 16kHz Int16 mono
- upload queue starts only after final `MediaRecorder` flush resolves
- Reconnect and ghost turn handling:
- reconnect after `turn.stop` but before `turn.committed` reconciles to server state
- stale local recordings are dropped if the server already advanced
- stale or spoofed `prompt_id` / `client_turn_id` is rejected
- Finish barrier:
- `session.finish` waits for listed pending uploads before review
- failed uploads are excluded from the wait barrier and degrade cleanly
- `beforeunload` warning appears while uploads remain pending
- DB ordering:
- artifact registration immediately after `turn.committed` succeeds because the transcript row is already committed
- Review behavior:
- final grading uses live transcript only in the normal path
- uploaded per-turn audio contributes to voice/audio evidence when present
- explicit live-STT failure path can recover a turn transcript from uploaded audio
## Assumptions And Defaults
- Scope is `services/interview-service` only.
- Backend relay websocket is the authoritative live transport; Gemini credentials stay server-side.
- Gemini Live is used for realtime transcription transport, not interviewer prompt generation.
- Gemini carries no authoritative interview state, so cold reconnect/rotation between turns is acceptable and preferred over depending on session resumption in v1.
- Final per-turn live transcript is the source of truth for realtime orchestration and final grading in the normal path.
- Uploaded turn audio is evidence and playback data, not a second grading transcript except for explicit live-STT recovery fallback.
- Official docs informing this plan:
- [Live API capabilities guide](https://ai.google.dev/gemini-api/docs/live-guide)
- [Session management with Live API](https://ai.google.dev/gemini-api/docs/live-session)
- [Live WebSockets API reference](https://ai.google.dev/api/live)
- [Get started with Live API](https://ai.google.dev/api/multimodal-live)

View File

@@ -0,0 +1,688 @@
# Roleplay Service Audio-First v0 Clone Plan
## Summary
- Ship `services/roleplay-service` by cloning the production-ready `services/interview-service` and making the smallest set of changes needed to support live audio-first roleplay.
- Reuse the same backend-owned Gemini Live WebSocket transport, turn persistence, artifact archival, storage, and asynchronous post-session review flow.
- Replace interview-specific planning, prompting, routing, and rubric logic with roleplay-specific equivalents.
- Persist every generated roleplay scenario separately so the generated plans and transcripts can later become the seed catalogue for curated scenarios.
## Confirmed Decisions
- Roleplay v0 is audio-first only.
- Facial, body, video, and screen-share analysis are out of scope for v0.
- Use a new audio-only roleplay rubric for v0.
- Keep the same live WebSocket streaming protocol as the interview service.
- Create a new scenario row for every configure request.
- `brief` is optional in the configure request.
- Reuse the interview DSPy planning path, but feed it a roleplay brief and store the full generated payloads.
## Goals
1. Launch a live roleplay service quickly by reusing the already-approved interview service architecture.
2. Preserve enough structure and generated data to evolve into a managed scenario catalogue later.
3. Keep the implementation surgical so production risk stays low.
4. Avoid introducing video and screen analysis complexity before the audio path is live.
## Non-Goals
- Video capture or storage.
- Screen-share capture or storage.
- Facial expression, body language, or visual technical quality scoring.
- Admin scenario management UI.
- Scenario reuse or deduplication logic.
- Full BRD parity for all roleplay metrics in v0.
## Baseline To Reuse From Interview Service
The following pieces from `services/interview-service` are already a strong foundation and should be cloned with minimal behavioral change:
- FastAPI app shell and health endpoint.
- Sync SQLAlchemy session management and DB initialization.
- Live WebSocket session loop in `app/api/session_ws.py`.
- Gemini Live relay in `app/services/live_relay.py`.
- Turn persistence for final assistant and candidate transcripts.
- Audio archive builder in `app/services/archive.py`.
- Storage upload service in `app/services/storage.py`.
- Background review generation scheduling and retry flow.
- Existing DSPy client structure for plan generation and review generation.
## High-Level Service Shape
Create a new service directory by copying `services/interview-service` to `services/roleplay-service`.
The initial structure stays intentionally similar:
- `app/main.py`
- `app/api/`
- `app/db/`
- `app/services/`
- `app/assets/`
- `tests/`
The aim is to keep as much of the runtime and deployment story identical as possible.
## Public API v0
All endpoints live under `/api/v1`.
### 1. Configure Roleplay
`POST /api/v1/roleplays/configure`
Purpose:
- Create a new scenario record.
- Create a new roleplay session.
- Run DSPy planning against a roleplay brief.
- Persist the generated scenario definition and session prompt plan.
Request payload:
```json
{
"user_id": "user-123",
"org_id": "org-456",
"persona_id": "emma",
"duration_minutes": 15,
"roleplay_type": "custom",
"brief": "optional freeform roleplay brief",
"metadata": {
"target_role": "Customer Success Manager",
"candidate_name": "Asha",
"experience_level": "mid"
}
}
```
Response payload:
```json
{
"session_id": "...",
"scenario_id": "...",
"config": {
"persona_id": "emma",
"duration_minutes": 15,
"roleplay_type": "custom",
"metadata": {}
},
"opening_prompt": "...",
"prompt_outline": [
{
"sequence": 1,
"prompt": "...",
"signals": ["..."],
"rubric_dimensions": ["voice", "content", "scenario_adherence"]
}
],
"scenario": {
"title": "...",
"setup": "...",
"constraints": [],
"success_criteria": []
}
}
```
### 2. Live Session WebSocket
`WS /api/v1/roleplays/session/{session_id}`
Purpose:
- Preserve the same proven transport contract from the interview service.
- Use the same client integration pattern as interview.
Client messages:
- `session.start`
- `audio.input`
- `session.finish`
Server messages:
- `session.ready`
- `assistant.audio`
- `assistant.transcript`
- `candidate.transcript`
- `turn.saved`
- `session.completed`
- `error`
### 3. Review Polling
`GET /api/v1/roleplays/review/{session_id}`
Purpose:
- Poll review status after `session.finish`.
- Return completed review payload and artifacts.
Response states:
- `processing`
- `completed`
- `failed`
Completed payload additions beyond interview:
- `certificate_eligible`
- `provider_payload` can remain stored in DB only for v0 unless explicitly exposed later
### 4. Optional Read Endpoints
These are low-risk and useful, but not required for the first implementation slice:
- `GET /api/v1/roleplays/personas`
- `GET /api/v1/roleplays/scenarios`
- `GET /api/v1/roleplays/scenarios/{scenario_id}`
## Data Model
The data model should stay close to the interview schema so the cloned service remains easy to reason about.
### New Table: `roleplay_scenarios`
Purpose:
- Persist every generated scenario independently.
- Capture the open-ended scenario brief and the generated planning payloads.
- Form the basis of a future reusable scenario catalogue.
Fields:
- `id`
- `org_id`
- `user_id`
- `persona_id`
- `roleplay_type`
- `brief_text`
- `scenario_payload` JSON
- `plan_payload` JSON
- `created_at`
- `updated_at`
Recommended `scenario_payload` shape:
```json
{
"title": "...",
"setup": "...",
"persona_role": "...",
"candidate_role": "...",
"success_criteria": ["..."],
"constraints": ["..."],
"tags": ["..."],
"difficulty": "..."
}
```
Recommended `plan_payload` shape:
```json
{
"greeting_text": "...",
"questions": ["..."],
"follow_up_policy": {},
"safety_guardrails": {},
"source": "dspy"
}
```
### Table: `roleplay_sessions`
Clone of `interview_sessions` with roleplay-specific naming and one extra link to the scenario row.
Fields:
- `id`
- `scenario_id`
- `user_id`
- `org_id`
- `roleplay_config` JSON
- `status`
- `planning_context` JSON
- `prompt_plan` JSON list
- `opening_prompt`
- `created_at`
- `updated_at`
- `completed_at`
Recommended `roleplay_config` contents:
- `persona_id`
- `duration_minutes`
- `roleplay_type`
- `metadata`
- `rubric_profile_id`
Recommended `planning_context` contents:
- `plan_input`
- `history_summary`
- `follow_up_policy`
- `scenario_payload`
- `plan_payload`
- `review_generation`
- `finalization_error`
- `session_termination`
### Table: `roleplay_turns`
Clone of `interview_turns`.
Fields:
- `id`
- `session_id`
- `sequence`
- `speaker`
- `turn_type`
- `transcript`
- `timing`
- `turn_metadata`
- `created_at`
### Table: `roleplay_artifacts`
Clone of `interview_artifacts`.
Fields:
- `id`
- `session_id`
- `artifact_type`
- `s3_key`
- `mime_type`
- `duration_ms`
- `size_bytes`
- `manifest_metadata`
- `created_at`
### Table: `roleplay_reviews`
Clone of `interview_reviews` with one additional field for raw provider output.
Fields:
- `id`
- `session_id`
- `overall_score`
- `rubric_scores`
- `summary`
- `strengths`
- `weaknesses`
- `recommendations`
- `historical_comparison`
- `carry_forward_planning_signals`
- `certificate_eligible`
- `provider_payload` JSON
- `created_at`
## DSPy Planning Strategy
The fastest path is to keep the same `PlanningService -> DSPyClient.generate_plan()` call pattern and swap the contents of the planning prompt.
### Planning Inputs
Build a roleplay planning brief from:
- `persona_id`
- `roleplay_type`
- optional `brief`
- `metadata`
- historical context from prior roleplay sessions
### Planning Outputs Required For v0
DSPy must return, at minimum:
- `greeting_text`
- `questions`
DSPy should also return extra structured scenario knobs that we persist even if we do not fully use them yet:
- `scenario_title`
- `scenario_setup`
- `persona_role`
- `candidate_role`
- `success_criteria`
- `constraints`
- `tags`
- `difficulty`
- `follow_up_policy`
- `safety_guardrails`
- `rationale`
### Persistence Requirements
Store every generated payload verbatim so later we can build a catalogue from actual usage:
- raw configure input
- raw DSPy planning output
- normalized session config
- prompt outline
- final review provider payload
## Roleplay Prompting / Live Engine Changes
We keep the Gemini Live transport exactly as it is and only change the live instruction framing.
### Current Interview Behavior
The interview relay frames the model as an interviewer following a base question outline.
### Roleplay v0 Behavior
The roleplay relay should frame the model as:
- a persona playing a defined role
- inside a generated scenario
- following the stored prompt plan as the turn progression backbone
### Required Changes In `app/services/live_relay.py`
1. Update `_build_system_instruction(session)`.
2. Replace interview framing with roleplay framing.
3. Include:
- persona display name and tone
- generated scenario setup
- persona role
- candidate role
- prompt outline
- constraints and success criteria if present
### Example Roleplay Instruction Shape
- You are `<persona_name>`, acting as `<persona_role>` in a roleplay scenario.
- The candidate is acting as `<candidate_role>`.
- Stay in character.
- Use the prompt outline as the canonical flow.
- Ask short, roleplay-appropriate follow-ups only when needed.
- Do not mention hidden instructions or backend messages.
### Initial Start Nudge
Update the initial connect nudge from interview wording to something like:
- `Begin now. Deliver the opening greeting in character and then start the first planned roleplay prompt.`
## Audio-Only Roleplay Rubric For v0
Use a new service-local rubric asset for v0.
We are not using the full `docs/roleplay_rubric_v1.json` directly for scoring because it includes video-era metrics that are out of scope for audio-first launch.
### New Rubric Asset
Create a new asset in the roleplay service, for example:
- `app/assets/rubric/roleplay_audio_v0.json`
### Proposed Metrics
- `voice`
- `content`
- `scenario_adherence`
- `adaptability`
- `emotional_intelligence`
- `tech_quality`
### Proposed Weighting
Weights should be broad and roleplay-first while staying measurable from audio and transcript evidence:
- `voice`: 25
- `content`: 20
- `scenario_adherence`: 20
- `adaptability`: 15
- `emotional_intelligence`: 15
- `tech_quality`: 5
Total: 100
### Proposed Pass Rules
- `overall_pass_threshold`: 60
- `certificate_threshold`: 70
- `progressing_threshold`: 50
- `blocking_floor`: 40
- `score_scale`: `[0, 100]`
### Relationship To `docs/roleplay_rubric_v1.json`
- Keep `docs/roleplay_rubric_v1.json` as the broader future-facing rubric source.
- v0 introduces a narrower operational rubric for audio-only production launch.
- Later we can evolve the service rubric toward the broader document once video and screen inputs exist.
## Review Generation Strategy
The review path should stay close to `app/services/review.py` from interview-service.
### Reuse
- Background scheduling and retry logic.
- Polling pattern.
- Artifact serialization.
- Historical comparison structure.
### Change
1. Swap rubric loader to the roleplay audio rubric.
2. Change metric keys and deterministic scoring heuristics.
3. Build a roleplay-specific review brief for DSPy.
4. Store the raw review payload in `provider_payload`.
5. Compute `certificate_eligible` from pass rules.
### Deterministic Evidence Inputs
Continue using transcript- and artifact-derived inputs similar to interview-service:
- filler count
- words per minute
- ownership markers
- quantified outcomes
- role and scenario keyword overlap
- duration and pacing
- audio artifact presence and manifest signals
### Historical Comparison
Same approach as interview-service:
- compare against most recent prior completed roleplay review for the same user and org
- compute overall delta
- compute per-metric deltas
### Carry-Forward Planning Signals
Keep these because they are useful for future scenario generation and progressive coaching:
- `focus_areas`
- `recurring_weak_areas`
- `weakness_summary`
## Minimal File-Level Implementation Plan
### Slice 1: Clone and Rename Service Identity
Create `services/roleplay-service` by copying `services/interview-service`.
Update:
- `pyproject.toml`
- `README.md`
- `Dockerfile`
- `docker-compose.yml`
- `app/main.py`
- `app/core/config.py`
Required renames:
- service title and package metadata
- database filename / DB name
- temp directory path
- storage bucket name
- local docker port
### Slice 2: Rename Data Layer
Update:
- `app/db/models.py`
- `app/db/session.py`
Tasks:
- rename interview models to roleplay models
- introduce `RoleplayScenario`
- add `certificate_eligible` and `provider_payload` to review model
- keep relationships otherwise parallel to interview
### Slice 3: Configure Endpoint And Planning
Update:
- `app/api/configure.py`
- `app/services/planning.py`
- `app/services/dspy_client.py`
- `app/services/assets.py`
Tasks:
- change route to `/roleplays/configure`
- accept `roleplay_type`, optional `brief`, and `metadata`
- persist a new `RoleplayScenario`
- create a linked `RoleplaySession`
- store the full DSPy outputs into both scenario and session context
### Slice 4: Live WebSocket Route
Update:
- `app/api/session_ws.py`
- `app/services/live_relay.py`
Tasks:
- change route path to `/roleplays/session/{session_id}`
- keep message protocol unchanged
- swap the system prompt framing to roleplay
- return `prompt_outline` and roleplay config in `session.ready`
### Slice 5: Artifacts And Storage Prefixes
Update:
- `app/services/archive.py`
Tasks:
- change artifact storage prefix from `interviews/...` to `roleplays/...`
- rename manifest keys from `interview_config` to `roleplay_config`
### Slice 6: Review Endpoint And Scoring
Update:
- `app/api/review.py`
- `app/services/review.py`
- `app/assets/rubric/roleplay_audio_v0.json`
Tasks:
- change route path to `/roleplays/review/{session_id}`
- compute roleplay metric scores using the audio-only rubric
- compute `certificate_eligible`
- persist `provider_payload`
### Slice 7: Tests
Clone and adapt the interview tests:
- `tests/test_configure.py`
- `tests/test_session_ws.py`
- `tests/test_review.py`
Required assertions:
- configure persists both scenario and session
- raw DSPy plan payload is stored
- WS session persists turns and uploads artifacts
- review returns roleplay metrics and certificate eligibility
## Concrete Data Contracts
### Configure Plan Storage In `planning_context`
Recommended shape:
```json
{
"plan_input": {
"roleplay_type": "custom",
"brief": "...",
"metadata": {}
},
"history_summary": {
"prior_session_count": 0,
"recent_weak_areas": [],
"recent_summaries": []
},
"follow_up_policy": {
"max_follow_ups_per_prompt": 1,
"max_follow_ups_per_session": 2,
"allowed_objectives": ["depth", "clarity", "example", "adaptation", "tone"]
},
"scenario_payload": {},
"plan_payload": {}
}
```
### Prompt Outline Shape
```json
[
{
"sequence": 1,
"prompt": "...",
"signals": ["dspy planned", "scenario focus: stakeholder tension"],
"rubric_dimensions": ["voice", "content", "scenario_adherence"]
}
]
```
### Review Response Shape
```json
{
"status": "completed",
"session_id": "...",
"overall_score": 78.4,
"rubric_scores": {
"voice": 81,
"content": 76,
"scenario_adherence": 79,
"adaptability": 72,
"emotional_intelligence": 80,
"tech_quality": 85
},
"summary": "...",
"strengths": ["..."],
"weaknesses": ["..."],
"recommendations": ["..."],
"historical_comparison": null,
"carry_forward_planning_signals": {
"focus_areas": ["adaptability"],
"recurring_weak_areas": [],
"weakness_summary": ["Could adapt faster to objections"]
},
"certificate_eligible": true,
"audio_artifacts": []
}
```
## Risks And Mitigations
### Risk 1: Roleplay Planning Is Too Open-Ended
Because scenario generation is intentionally open, outputs may be inconsistent.
Mitigation:
- enforce a structured DSPy JSON schema
- persist all plan payloads for later tuning
- keep prompt outline authoritative for the live session
### Risk 2: Prompt Drift During Live Session
The live model may improvise away from the scenario.
Mitigation:
- make prompt outline explicit in system instruction
- instruct the model to stay in character and use the outline as the canonical flow
### Risk 3: Review Rubric Expectations Drift From BRD
Audio-only v0 will not match the broader visual roleplay rubric.
Mitigation:
- use a dedicated operational audio rubric for v0
- keep the broader doc rubric intact for later phases
### Risk 4: Scenario Table Could Grow Quickly
Every configure request creates a new scenario row.
Mitigation:
- this is intentional in v0
- later introduce scenario grouping, dedupe, or promotion-to-catalogue workflows
## Test Plan
### Configure
- accepts optional `brief`
- persists a `RoleplayScenario`
- persists a linked `RoleplaySession`
- stores raw DSPy `scenario_payload` and `plan_payload`
- returns `opening_prompt` and `prompt_outline`
### WebSocket Live Session
- rejects missing session id
- rejects invalid session state transition
- starts roleplay session successfully
- persists assistant and candidate final transcripts
- builds and uploads artifacts on `session.finish`
- schedules review generation
### Review
- returns `processing` before review exists
- returns `failed` when generation fails
- returns `completed` with roleplay rubric scores
- returns `certificate_eligible`
- returns artifact list
## Rollout Shape
### Phase A
- land the new service with configure + live WS + review
- keep only personas as asset-backed read data
- scenarios are generated on demand and stored every time
### Phase B
- add read endpoints for generated scenarios
- analyze stored plans and transcripts to identify reusable patterns
### Phase C
- curate generated scenarios into a controlled catalogue
- introduce guardrails, scenario templates, and reuse flows
- expand rubric toward visual and screen-aware metrics once media inputs exist
## Recommended First Execution Order
1. Clone `interview-service` into `roleplay-service`.
2. Rename config, DB models, and storage prefixes.
3. Add `RoleplayScenario` and wire configure persistence.
4. Swap planning prompt and configure endpoint.
5. Swap live relay prompt framing.
6. Add audio-only roleplay rubric and review logic.
7. Adapt tests and run them.
## Definition Of Done For v0
- `services/roleplay-service` exists and boots independently.
- A client can configure a roleplay session with an optional brief.
- A live audio session runs over the same WS protocol as interview-service.
- Final transcripts, artifacts, scenario payloads, and plan payloads are persisted.
- Post-session review completes using the audio-only roleplay rubric.
- Review output includes `certificate_eligible`.
- The implementation remains close enough to interview-service that future maintenance is straightforward.

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,335 @@
**GrowQR**
**COURSE SERVICE**
Business Requirements Document • v2.0 • March 2026
| Upskilling Module • Microservice Specification Three-Phase Courseware Strategy • No Proprietary LMS |
| :---: |
| Document Title | Course Service — Business Requirements Document |
| :---- | :---- |
| Service Type | Standalone Microservice (Part of Upskilling Services) |
| :---- | :---- |
| Version | |
| :---- | :---- |
| Integration | Shares data with Roleplay, Interview, Assessment, Pathways \+ Dashboard |
| :---- | :---- |
| Courseware Strategy | Three-phase: External Index → Third-Party Creator → GenAI IP Generation |
| :---- | :---- |
| LMS Approach | No proprietary LMS. Integrates with Coursera, Moodle, Thinkific and others |
| :---- | :---- |
| 1\. SERVICE OVERVIEW |
| :---- |
The Course Service provides a curated learning library with external provider integrations and community-created content. Users enroll using credits, track progress, and earn certificates upon completion. GrowQR does not build a proprietary LMS — all courseware delivery relies on third-party platforms and a three-phase strategy to progressively own intellectual property.
## **1.1 Core Features**
• Three-phase courseware strategy: External mapping → Third-party creation → GenAI IP generation
• No proprietary LMS: Integration with Coursera, Moodle, Thinkific, LinkedIn Learning
• Course catalog with external provider integrations and community scenarios
• AI-powered recommendations based on skill gaps from Assessment, Interview, Roleplay, Q-Score
• Credit-based enrolment tracking: In Progress / Completed / Abandoned
• Certificate generation upon course completion (eligible courses only)
• Persona-driven content mapping across 2025 unique user profiles, industries, and life stages
| 2\. THREE-PHASE COURSEWARE STRATEGY |
| :---- |
The courseware strategy follows a deliberate, staged approach that builds toward platform intellectual property (IP) through GenAI-generated, persona-driven content. Each phase unlocks the next.
| PHASE 1: External Mapping & Indexing |
| :---- |
| • Map user personas to purchased or indexed external courses (e.g., Coursera, LinkedIn Learning, Udemy) |
| • Users browse a curated catalog; GrowQR surfaces the most relevant content per role, industry, and Q-Score gap |
| • Course metadata indexed: title, provider, duration, difficulty, skills covered, rating, price |
| • AI recommendation engine selects top matches from external catalog based on skill gap analysis |
| • Revenue model: Affiliate commissions from enrolled courses via provider APIs |
| • No content creation required — pure aggregation and curation layer |
| PHASE 2: Third-Party Creator Platform |
| :---- |
| • Platform opens to third parties: Heads of Departments (HODs), corporates, and subject matter experts |
| • Creators bundle and publish their own content within the GrowQR platform |
| • Content types: Video modules, guided projects, assessments, case studies |
| • GrowQR provides creator tools, hosting (via Moodle / Thinkific integration), and distribution |
| • Revenue model: Revenue share with creators; premium access tiers for corporate bundles |
| • Quality control: Community ratings, completion rates, and AI-driven content scoring |
| • Enables industry-specific content that external platforms do not cover |
| PHASE 3: GenAI IP Generation (Intellectual Property) |
| :---- |
| • Full-blown personalised course generation using Generative AI |
| • Content defined by 2025 unique user personas, mapped to industry, role, and life stage |
| • Each persona receives a structured, distinct learning path — not just filtered external content |
| • GrowQR owns this content as platform IP: structured curricula, assessments, and roleplay scenarios |
| • Life stage mapping: College student → First job → Career pivot → Leadership → Entrepreneurship |
| • Industry mapping: Tech, Finance, Healthcare, Marketing, Operations, Creative, etc. |
| • GenAI generates course scripts, quizzes, scenario prompts, and practice exercises on demand |
| • This phase creates the long-term competitive moat and differentiated platform identity |
| 3\. FUNCTIONS |
| :---- |
## **FUNCTION 1: Course Discovery & Catalog**
**3.1.1 Course Sources (by Phase)**
| Phase | Source | Description |
| :---- | :---- | :---- |
| Phase 1 | Coursera, LinkedIn Learning, Udemy, edX | Externally indexed courses mapped to user personas and Q-Score gaps |
| Phase 1 | Internal Fallback / Question Bank | GrowQR-curated content when external APIs are unavailable |
| Phase 2 | HODs, Corporates, Subject Matter Experts | Third-party content created and hosted via Moodle / Thinkific |
| Phase 2 | Community Scenarios | User-generated learning content, peer-reviewed and rated |
| Phase 3 | GenAI Generated (GrowQR IP) | Fully personalised courses generated from 2025 user personas by GenAI |
**3.1.2 Persona Mapping (Phase 3 Foundation)**
Course content is structured around 2025 distinct user personas. Each persona is defined by the intersection of:
• Role category (e.g., Software Engineer, Product Manager, Sales Leader)
• Industry (e.g., FinTech, Healthcare, E-commerce, SaaS)
• Life stage (e.g., College student, Early career, Career pivot, Leadership track, Entrepreneur)
• Q-Score profile (which of the 25 Q-Scores are high, low, or developing)
• Motivation archetype (Technical Specialist, Strategic Leader, Creative Innovator, etc.)
**3.1.3 Data Requirements**
| Field | Description |
| :---- | :---- |
| Course ID | Unique identifier |
| Title | Course name |
| Provider | Coursera, LinkedIn Learning, Moodle, Thinkific, GrowQR IP, etc. |
| Phase | 1 (External) / 2 (Third-Party) / 3 (GenAI IP) |
| Type | Full Course / Guided Project / Micro-module |
| Persona Tags | Array of persona IDs this course maps to |
| Q-Score Tags | Which Q-Scores this course develops |
| Life Stage | College / Early Career / Pivot / Leadership / Entrepreneur |
| Duration | Estimated time to complete |
| Difficulty | Beginner / Intermediate / Advanced |
| Certificate Available | Boolean — awards certificate on completion? |
| Credit Cost | Free (1 credit) / Guided Project (2 credits) / Full Course (3 credits) |
## **FUNCTION 2: Course Enrolment**
**3.2.1 Enrolment Flow**
1\. User selects course → System checks: credits available, not already enrolled
2\. Credit deducted based on course type
3\. Enrolment record created: User ID, Course ID, Start date, Phase, Status (In Progress)
4\. External courses: Redirect to provider platform with tracking link
5\. Phase 3 / Internal courses: Delivered natively within GrowQR
**3.2.2 Credit Costs**
• Free courses: 1 credit to enrol
• Guided Projects: 2 credits
• Full Courses: 3 credits
• GenAI IP courses (Phase 3): Credit cost TBD based on persona depth
## **FUNCTION 3: Progress Tracking & Certificates**
• Track enrolment status: In Progress / Completed / Abandoned
• External courses (Phase 1): Webhook from provider OR periodic sync
• Third-party courses (Phase 2): Progress tracked via Moodle / Thinkific integration
• GenAI IP courses (Phase 3): Module-level completion tracked natively
• Certificate issued when: Course completed AND Certificate Available \= true
• Certificate includes: User name, Course title, Provider/Phase, Completion date, Certificate ID
## **FUNCTION 4: AI-Powered Recommendations**
**3.4.1 Recommendation Logic**
• Analyse data from Assessment, Interview, and Roleplay services
• Identify Q-Score gaps and map to relevant course tags
• Cross-reference user persona profile (role, industry, life stage, archetype)
• Prioritise: Highest-rated courses, best persona match, free courses first
• Phase 3 courses prioritised for users with established Q-Score histories
**3.4.2 Data Inputs**
• Assessment results: Low-scoring topics and Q-Score contributions
• Interview feedback: Weak areas identified
• Roleplay performance: Scenarios user struggles with
• User profile: Career goals, current role, life stage, archetype
• Pathway data: Current week in cycle and progression phase (Learn vs. Apply ratio)
| 4\. DATA SHARING WITH OTHER SERVICES |
| :---- |
| Target Service | Data Shared | Purpose |
| :---- | :---- | :---- |
| Assessment Service | Courses completed, topics learned | Re-test user on completed course topics to show improvement |
| Interview Service | Course completion, skills learned | Tailor interview questions to validate learning |
| Roleplay Service | Course completion, skills practiced | Suggest roleplay scenarios for learned skills |
| Pathways Service | Enrolment count, completed courses, Q-Score signals | Adjust weekly cycle priorities and learning/apply ratio |
| Dashboard Service | Enrolment count, completed courses, certificates earned | Update Q-Score, display achievements and progress |
| Job Matchmaking | Skills learned, certifications, course completion signals | Improve opportunity match quality and relevance |
| 5\. TECHNICAL REQUIREMENTS |
| :---- |
## **5.1 External API Integrations**
| Provider | Phase | Integration Method |
| :---- | :---- | :---- |
| Coursera | Phase 1 | Coursera Catalog API \+ affiliate tracking |
| LinkedIn Learning | Phase 1 | LinkedIn Learning API |
| Udemy | Phase 1 | Udemy Affiliate API |
| edX | Phase 1 | edX API |
| Moodle | Phase 2 | Moodle REST API \+ Webhook for completion tracking |
| Thinkific | Phase 2 | Thinkific API \+ Embed for third-party creator content |
| GrowQR GenAI | Phase 3 | Internal LLM pipeline — on-demand course generation |
## **5.2 Performance Requirements**
| Operation | Target SLA |
| :---- | :---- |
| Course catalog load | \< 2 seconds |
| Enrolment processing | \< 1 second (after credit check) |
| AI course recommendation | \< 2 seconds |
| Certificate generation | \< 3 seconds after completion |
| External provider sync (Phase 1\) | \< 5 seconds |
| Moodle / Thinkific sync (Phase 2\) | \< 10 seconds |
| GenAI course generation (Phase 3\) | \< 30 seconds for full micro-module |
| 6\. ACCEPTANCE CRITERIA |
| :---- |
| \# | Must Pass | Pass / Fail |
| :---- | :---- | :---- |
| **1** | Phase 1: All courses load from external APIs (Coursera, Udemy, LinkedIn Learning). Filters and persona mapping work. | \[ \] PASS \[ \] FAIL |
| **2** | Phase 2: Moodle and Thinkific integrations functional. Third-party creators can publish and bundle content. | \[ \] PASS \[ \] FAIL |
| **3** | Phase 3: GenAI generates structured micro-courses for at least 5 validated personas. Content is unique and role-specific. | \[ \] PASS \[ \] FAIL |
| **4** | Credits deducted correctly on enrolment. Enrolment record created. External redirect works. | \[ \] PASS \[ \] FAIL |
| **5** | Progress status updates correctly for all three phases. External sync works or shows last known state. | \[ \] PASS \[ \] FAIL |
| **6** | Certificates generated for eligible completed courses. Download link works. | \[ \] PASS \[ \] FAIL |
| **7** | AI recommends relevant courses based on Q-Score gaps, persona profile, and pathway cycle phase. | \[ \] PASS \[ \] FAIL |
| **8** | Completion data and Q-Score signals shared with all connected services. Dashboard receives course count. | \[ \] PASS \[ \] FAIL |
| **9** | Persona mapping covers minimum 20 distinct profiles across role, industry, and life stage dimensions. | \[ \] PASS \[ \] FAIL |
| **10** | Pathway integration: Course recommendations align with current weeks learn/apply ratio in the weekly cycle. | \[ \] PASS \[ \] FAIL |

View File

@@ -0,0 +1,76 @@
| GrowQR Interview Service — One-Pager Avatar-Based AI Interviewers \+ Video/Voice \+ Screen Share | v3 | INTERVIEW |
| :---- | :---: |
| PURPOSE |
| ----- |
| AI-powered mock interviews with 4 avatar-based interviewers (Payal, Emma, John, Kapil) that speak using real-time voice synthesis. Users recorded via video/audio and can share screen for coding tests/technical demos. Comprehensive analysis across 6 metrics (Intro, Facial Expression, Body Language, Language, Voice including filler word count, Outro) \+ Technical Quality (lighting, framing, background, audio). Historical comparison tracks improvement over time. |
| CORE FEATURES | |
| :---: | :---- |
| **1** | 4 AI Interviewer Avatars: Payal (warm, friendly), Emma (professional, structured), John (authoritative, challenging), Kapil (casual, conversational) \- each with distinct voice |
| **2** | Real-Time Voice Synthesis: AI interviewers SPEAK all questions with personality-matched voices and natural intonation |
| **3** | Interview Types: Warm Up (Non-technical), Coding (Programming), Role-Related (Technical), Behavioral (HR) |
| **4** | Duration Tiers: 5 mins (1 credit), 15 mins (2 credits \- Premium), 30 mins (3 credits \- Premium) |
| **5** | Screen Share: User shares specific window for coding tests, technical demos, presentations |
| **6** | 7-Metric Analysis: Intro (10%), Facial Expression (20%), Body Language (20%), Language (15%), Voice (20% \- includes filler word count), Outro (10%), Technical Quality (5%) |
| **7** | Historical Comparison: Track improvement across multiple interviews with trend analysis |
| USER JOURNEY | | | |
| :---: | ----- | ----- | ----- |
| **Step** | **User Action** | **System Response** | **Data Captured** |
| **1** | User configures interview | Validate: type, duration, persona, credits | Config parameters |
| **2** | User starts interview | Deduct credits, load avatar, request permissions | Session ID, Credits deducted |
| **3** | Avatar speaks greeting | Voice synthesis: "Hello\! I'm your AI interviewer..." | Timer starts, Recording begins |
| **4** | User shares screen (optional) | Capture window, start screen analysis | Screen recording, Window type |
| **5** | Avatar speaks question | Voice synthesis with lip-sync | Question logged |
| **6** | User responds (voice/text) | Capture video/audio, analyze filler words, process screen | Transcript, Filler count, Technical quality, Screen |
| **7** | Session ends | Stop recordings, trigger analysis | End time, Completion status |
| **8** | Analysis completes | Calculate 7 metrics, compare to history | All metric scores \+ historical comparison |
| KEY STATES TO HANDLE | | |
| ----- | ----- | ----- |
| **State** | **Condition** | **System Behavior** |
| **Permission Denied** | User blocks camera/mic | Error: 'Camera/mic required. Screen share optional for coding.' |
| **Avatar Loading** | Persona initializing | Show: 'Preparing interview with \[Name\]...' (5-10s) |
| **Active Interview** | Session in progress | Avatar speaks, user responds, timer running |
| **Screen Share Active** | User sharing window | Screen content captured and analyzed |
| **AI Service Error** | AI unavailable | Show error, use fallback questions |
| **Voice Synthesis Error** | TTS fails | Fallback: text bubbles |
| **Analysis Processing** | Calculating metrics | Show: 'Analyzing...' (30-60s) |
| **Results Ready** | Analysis complete | Display 7 metrics \+ screen \+ historical \+ recommendations |
| ANALYSIS METRICS | |
| ----- | ----- |
| **Metric** | **What's Analyzed** |
| **Intro (10%)** | Opening greeting quality, confidence, first impression, professionalism |
| **Facial Expression (20%)** | Engagement, authenticity, eye contact, smile appropriateness, emotional state |
| **Body Language (20%)** | Posture, Gestures, Professionalism, Fidgeting, Movement patterns |
| **Language (15%)** | Grammar, Vocabulary, Clarity, Sentence structure, Articulation |
| **Voice (20%)** | Tone, Pace (WPM), Volume, Filler words COUNT (um, uh, like, you know), Vocal confidence |
| **Outro (10%)** | Closing statement, Questions to interviewer, Professionalism, Final impression |
| **Technical Quality (5%)** | Lighting: Well-lit/Poor | Framing: Centered/Off | Background: Professional/Distracting | Audio: Clear/Noisy |
| **Screen Content** | Code: Syntax, Structure, Logic | Presentations: Quality, Clarity | Demos: Completeness |
| DATA SHARING WITH OTHER SERVICES | | |
| ----- | ----- | ----- |
| **Target Service** | **Data Shared** | **Purpose** |
| **Roleplay Service** | Communication gaps, weak types, low scores, filler patterns | Suggest roleplay scenarios for weak areas |
| **Assessment Service** | Technical gaps, low topics, code quality issues | Recommend assessments for validation |
| **Course Service** | Skill gaps, low metrics, coding weaknesses | Recommend courses (interview prep, communication, technical) |
| **Dashboard Service** | Interview count, scores across 7 metrics, trends, code analysis | Update Q-Score, show progress, achievements |
| ACCEPTANCE CRITERIA | | |
| :---: | ----- | :---: |
| **\#** | **Must Pass** | **Pass/Fail** |
| **1** | All 4 personas render correctly. Voice synthesis works with distinct voices and lip-sync. | \[ \] PASS \[ \] FAIL |
| **2** | All interview types selectable. Premium durations tier-gated with upgrade prompts. | \[ \] PASS \[ \] FAIL |
| **3** | Video/audio captured throughout. Stored in cloud. Download links work. | \[ \] PASS \[ \] FAIL |
| **4** | User can share specific window. Screen recording works. Can stop/resume sharing. | \[ \] PASS \[ \] FAIL |
| **5** | AI analyzes voice with filler word COUNT. Count displayed in feedback. | \[ \] PASS \[ \] FAIL |
| **6** | AI analyzes technical quality: Lighting, Framing, Background, Audio. Ratings displayed. | \[ \] PASS \[ \] FAIL |
| **7** | AI analyzes screen content: Code quality, Presentation quality, Demo completeness. | \[ \] PASS \[ \] FAIL |
| **8** | All 7 metrics calculated correctly. Analysis completes within 60s. | \[ \] PASS \[ \] FAIL |
| **9** | Historical comparison works: Shows previous scores with dates vs current. Includes all metrics. | \[ \] PASS \[ \] FAIL |

View File

@@ -0,0 +1,71 @@
| GrowQR Roleplay Service — One-Pager Avatar-Based AI \+ Real-Time Video/Voice \+ Screen Share | v3 | ROLEPLAY |
| :---- | :---: |
| PURPOSE |
| ----- |
| Avatar-based AI roleplay with real-time video/audio/screen interaction. AI personas speak using voice synthesis. Users respond via voice/text and can share screen (specific window) for coding/presentation demos. System analyzes voice (including filler word count), facial expressions, body language, technical setup quality (lighting, framing), and screen content to provide comprehensive performance feedback and certificates. |
| CORE FEATURES | |
| :---: | :---- |
| **1** | Avatar-Based AI Personas: Visual characters with voice synthesis, lip-sync, emotional expressions |
| **2** | Real-Time Voice Synthesis: AI persona SPEAKS all questions and responses (not just text bubbles) |
| **3** | Video/Audio Recording: Capture user's camera and microphone throughout entire session |
| **4** | Screen Share: User shares specific window (IDE, slides, demo app) \- NOT full desktop |
| **5** | AI Screen Content Analysis: Analyzes code quality (syntax, logic), presentation slides, demos |
| **6** | Comprehensive Analysis: Voice (tone, pace, filler word count), Facial (engagement, eye contact), Body (posture, gestures), Technical Quality (lighting, framing, background), Screen content |
| **7** | Performance Scoring: Voice 35%, Facial 25%, Body Language 20%, Technical Quality 10%, Content 10% |
| USER JOURNEY | | | |
| :---: | ----- | ----- | ----- |
| **Step** | **User Action** | **System Response** | **Data Captured** |
| **1** | User selects scenario | Load AI persona avatar, request camera/mic/screen permissions | Scenario ID, User ID |
| **2** | Permissions granted | Initialize avatar rendering, voice synthesis, recording systems | Media access granted |
| **3** | Session starts | Deduct 1 credit, start all recording (video/audio/screen), avatar speaks first question | Session ID, Start time, Recording streams |
| **4** | User shares screen (optional) | Capture specific window, begin screen content analysis | Screen recording, Content type detected |
| **5** | User responds (voice/text) | Capture response, AI analyzes voice/facial/body/technical/screen in real-time or queued | Transcript, Voice metrics (including filler count), Facial timeline, Body timeline, Technical quality (lighting/framing), Screen analysis |
| **6** | AI persona responds | Voice synthesis speaks follow-up, avatar lip-syncs | Conversation flow |
| **7** | Session completes | Stop all recordings, finalize analysis, calculate scores across all metrics | Overall score, Voice 88%, Facial 75%, Body 82%, Technical 90%, Screen 85% |
| KEY STATES TO HANDLE | | |
| ----- | ----- | ----- |
| **State** | **Condition** | **System Behavior** |
| **Permission Denied** | User blocks camera/mic/screen | Show error: 'Camera, microphone required. Screen share optional but recommended.' |
| **Media Loading** | Avatar/voice/recording initializing | Show: 'Preparing your session...' with progress (5-10s) |
| **Connection Unstable** | Poor network, dropped frames/audio | Degrade quality or switch to text-only mode, continue session |
| **Voice Synthesis Error** | TTS service fails | Fallback: Display text bubbles instead of speaking, avatar remains visible |
| **Screen Share Stopped** | User stops sharing mid-session | Continue session without screen analysis, note in results |
| **Active Session** | Roleplay in progress | Avatar speaks, user responds, all recording/analysis systems active |
| **Analysis Complete** | Post-session processing done | Display all scores: Voice, Facial, Body Language, Technical Quality, Screen Content (if shared), Overall |
| ANALYSIS METRICS | |
| ----- | ----- |
| **Metric** | **What's Analyzed** |
| **Voice (35%)** | Tone (friendly/professional), Pace (WPM), Clarity (articulation), Confidence (vocal strength), Filler words COUNT (um, uh, like, you know) |
| **Facial Expression (25%)** | Smile frequency, Eye contact (camera gaze), Emotional state (neutral/happy/stressed), Engagement level |
| **Body Language (20%)** | Posture (upright/slouched), Gestures (open/closed), Fidgeting, Professionalism rating |
| **Technical Quality (10%)** | Lighting: Well-lit/Acceptable/Poor | Framing: Centered in frame/Off-center | Background: Professional/Neutral/Distracting | Audio quality: Clear/Background noise |
| **Content Quality (10%)** | Relevance, Completeness, Accuracy of responses |
| **Screen Content (if shared)** | Code: Syntax, structure, logic, best practices | Presentations: Slide design, clarity | Demos: Feature completeness, explanation quality |
| **Overall Performance** | Weighted combination of all metrics with historical comparison to track improvement |
| DATA SHARING WITH OTHER SERVICES | | |
| ----- | ----- | ----- |
| **Target Service** | **Data Shared** | **Purpose** |
| **Interview Service** | Voice/facial/body/technical/screen scores, weak communication areas, filler word patterns | Tailor interview questions to address roleplay gaps |
| **Assessment Service** | Topic performance, behavioral competencies, communication patterns, technical setup quality | Recommend targeted assessments for weak areas |
| **Course Service** | Skill gaps (communication, presentation, technical), low metric scores, setup quality issues | Recommend soft skills, communication, technical courses, setup guidance |
| **Dashboard Service** | Session count, certificates earned, performance scores (all metrics), credits remaining | Update Q-Score based on performance, show progress achievements, suggest improvements |
| ACCEPTANCE CRITERIA | | |
| :---: | ----- | :---: |
| **\#** | **Must Pass** | **Pass/Fail** |
| **1** | Avatar renders correctly. Voice synthesis works with lip-sync within 100ms. Fallback to text if voice fails. | \[ \] PASS \[ \] FAIL |
| **2** | User camera/microphone captured throughout session. All recordings stored in cloud. Download links work. | \[ \] PASS \[ \] FAIL |
| **3** | User can share specific window. Screen recorded alongside video/audio. User can stop sharing anytime. | \[ \] PASS \[ \] FAIL |
| **4** | AI analyzes voice including filler word COUNT (um, uh, like, you know). Counts displayed in feedback. | \[ \] PASS \[ \] FAIL |
| **5** | AI analyzes technical quality: Lighting (well-lit/acceptable/poor), Framing (centered/off-center), Background (professional/distracting), Audio quality (clear/noisy). | \[ \] PASS \[ \] FAIL |
| **6** | AI analyzes screen content: Code quality (syntax, structure, logic) for IDEs, Slide quality (design, clarity) for presentations, Demo completeness for apps. | \[ \] PASS \[ \] FAIL |
| **7** | All metrics calculated correctly (Voice, Facial, Body, Technical Quality, Screen Content). Overall weighted score accurate. Certificate generated for 70%+ on eligible scenarios. | \[ \] PASS \[ \] FAIL |

View File

@@ -0,0 +1,153 @@
{
"rubric_profile_id": "text_roleplay_interview_v1",
"rubric_version": "2026-03-31",
"session_mode": "roleplay",
"metrics": {
"voice": {
"weight": 25,
"blocking_floor": 2,
"evidence_expectations": ["tone", "pace", "filler_words", "vocal_confidence"]
},
"facial": {
"weight": 20,
"blocking_floor": 2,
"evidence_expectations": ["facial_expressions", "eye_contact", "expressiveness"]
},
"body": {
"weight": 15,
"blocking_floor": 2,
"evidence_expectations": ["posture", "gestures", "body_language"]
},
"tech_quality": {
"weight": 5,
"blocking_floor": 2,
"evidence_expectations": ["audio_clarity", "video_clarity", "connection_stability"]
},
"content": {
"weight": 8,
"blocking_floor": 2,
"evidence_expectations": ["psi_structure", "specific_examples", "ownership", "impact"]
},
"scenario_adherence": {
"weight": 15,
"blocking_floor": 2,
"evidence_expectations": ["role_engagement", "context_awareness", "boundary_respect"]
},
"adaptability": {
"weight": 10,
"blocking_floor": 2,
"evidence_expectations": ["ai_persona_response", "in_session_learning", "pivot_ability"]
},
"emotional_intelligence": {
"weight": 10,
"blocking_floor": 2,
"evidence_expectations": ["empathy_demonstration", "tone_matching", "emotional_awareness"]
}
},
"pass_rules": {
"overall_pass_threshold": 60,
"certificate_threshold": 70,
"progressing_threshold": 50,
"blocking_floor": 2,
"score_scale": [1, 5],
"blocking_rule": "Any single metric scoring 1 (Needs Major Work) blocks passing regardless of overall weighted score"
},
"evidence_expectations": {
"deterministic": [
"word_count",
"duration_seconds",
"pacing_words_per_minute",
"filler_word_count_per_minute",
"scenario_keyword_overlap",
"role_keyword_overlap",
"psi_structure_completeness",
"ownership_marker_count",
"quantified_number_count",
"structural_marker_count"
],
"dspy": [
"voice_quality",
"tone_appropriateness",
"pace_consistency",
"filler_control",
"facial_expressiveness",
"eye_contact_maintenance",
"body_language_awareness",
"content_clarity",
"example_quality",
"ownership_strength",
"impact_demonstration",
"scenario_engagement",
"role_fidelity",
"adaptation_quality",
"in_session_learning",
"empathy_score",
"emotional_tone_match",
"tech_quality_score"
],
"video": [
"facial_expressiveness_score",
"eye_contact_ratio",
"posture_score",
"gesture_frequency",
"video_clarity_score",
"background_appropriateness"
],
"audio": [
"clarity_score",
"noise_level",
"pace_consistency",
"filler_density",
"vocal_confidence",
"tone_stability"
]
},
"scenario_type_overrides": {
"informational_interview": {
"adjustments": {
"content": {"weight_increase": 5, "min_score": 3},
"scenario_adherence": {"weight_decrease": 5}
},
"certificate_eligible": true
},
"client_feedback": {
"adjustments": {
"emotional_intelligence": {"weight_increase": 5, "min_score": 3},
"voice": {"weight_decrease": 5}
},
"certificate_eligible": true
},
"team_conflict": {
"adjustments": {
"emotional_intelligence": {"weight_increase": 5, "min_score": 3},
"adaptability": {"weight_increase": 5, "min_score": 3}
},
"certificate_eligible": false
},
"leadership_elevator_pitch": {
"adjustments": {
"voice": {"weight_increase": 5, "min_score": 3},
"content": {"weight_increase": 5, "min_score": 3}
},
"certificate_eligible": false
}
},
"sub_criteria": {
"psi_structure": {
"embedded_in": "content",
"description": "Problem → Solution → Impact structured explanation",
"evidence_expectations": ["problem_identification", "solution_approach", "measured_outcome"]
},
"screen_content": {
"embedded_in": "content",
"conditional": true,
"activates_on": "screen_share_used",
"description": "Code, slides, or demo quality when screen sharing"
},
"in_session_learning": {
"embedded_in": "adaptability",
"description": "Measurable improvement after AI persona correction mid-scenario",
"learning_concern_threshold": "failure_to_improve_after_two_consecutive_hints"
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,407 @@
# Interview Service Rebuild Plan
## Summary
Rebuild `interview-service` from scratch in its canonical location under `services/` and preserve the current implementation as a reference-only archive.
This plan intentionally replaces the older avatar-heavy and client/media-split direction with a much smaller phase-1 service focused on:
- interview configuration and planning
- one Gemini Live session path
- transcript and turn persistence
- dual-track audio archival with S3 upload
- rubric-based review generation with historical comparison
The rebuilt service remains named `interview-service`. There is no `v2` naming in code, docs, or runtime configuration.
## Goals
- Keep the public API to exactly 3 surfaces:
- `POST /configure`
- `WS /session/{session_id}`
- `GET /review/{session_id}`
- Preserve the product behaviors that matter:
- persona- and interview-aware planning
- bounded historical context reuse
- Gemini Live interview execution
- rubric scoring and review generation
- S3 archival of session audio artifacts
- historical comparison and carry-forward planning signals
- Remove operational and architectural bloat from phase 1.
## Non-Goals
The phase-1 rebuild explicitly excludes:
- avatars
- screen share
- technical-quality video analysis
- Redis
- SSE
- external job queues or workers
- demo app code
- multi-mode runtimes
- fallback-heavy abstractions
Audio-only interviewing is the only live mode in scope.
## Repository Transition
The repo transition should happen before implementation starts:
1. Rename the current service folder from `services/interview-service` to `services/interview-service-reference`.
2. Create a fresh `services/interview-service` folder beside it.
3. Treat `interview-service-reference` as a source of assets and selected logic only.
4. Do not refactor in place from the archived codebase.
Reference code may be copied only when it directly supports the reduced phase-1 scope, primarily:
- personas
- prompts
- rubric definitions
- selected planning logic
- selected review/scoring logic
## Target Service Shape
Build a small FastAPI service with a narrow, obvious structure:
```text
services/interview-service/
app/
api/
configure.py
session_ws.py
review.py
assets/
personas/
prompts/
rubric/
services/
planning.py
gemini_live.py
review.py
audio_archive.py
storage.py
db/
models.py
session.py
core/
config.py
logging.py
main.py
alembic/
tests/
```
Guiding rule: each module should map to one durable service concern. Avoid framework layers that exist only for optionality that phase 1 does not need.
## Public API
### `POST /configure`
Responsibilities:
- validate persona, interview type, duration, and context
- load bounded historical review context for the user
- build the interview plan using current config plus retained history signals
- persist the session row before live execution begins
Response should return:
- `session_id`
- normalized configuration
- opening prompt
- ordered question outline
- history summary used for planning
Planning output should remain explicit and bounded:
- opening prompt
- ordered base questions
- follow-up policy
- focus areas influenced by history
### `WS /session/{session_id}`
This is the only live runtime path in phase 1.
Accepted inbound events:
- `session.start`
- `audio.input`
- `session.finish`
Outbound events:
- `session.ready`
- `assistant.transcript`
- `assistant.audio`
- `candidate.transcript`
- `turn.saved`
- `session.completed`
- `error`
Responsibilities:
- attach to the persisted session
- run Gemini Live relay for the interview
- persist turns as they occur
- write assistant and candidate audio into the archive pipeline
- finalize artifacts and upload to S3 on `session.finish`
- mark the session complete
- start in-process async review generation after completion
### `GET /review/{session_id}`
Behavior:
- return `status: processing` until review generation finishes
- return the final review payload when available
Final payload should include:
- overall score
- rubric scores
- strengths
- weaknesses
- recommendations
- historical comparison
- carry-forward planning signals
- audio artifact metadata
This endpoint is read-only. It does not trigger new work.
## Data Model
Keep only 4 tables.
### `interview_sessions`
Fields:
- session id
- user and org identifiers
- interview configuration JSON
- status
- planning context JSON
- question plan JSON
- opening prompt
- created/updated/completed timestamps
Purpose:
- own the session lifecycle
- preserve normalized planning inputs and outputs
### `interview_turns`
Fields:
- session id
- sequence
- speaker
- turn type
- transcript
- timing metadata
- Gemini or session metadata JSON
Purpose:
- preserve ordered transcript and turn-level execution state
### `interview_artifacts`
Fields:
- session id
- artifact type
- S3 key
- mime type
- duration and size
- manifest metadata JSON
- created timestamp
Purpose:
- register all persisted review-related artifacts
### `interview_reviews`
Fields:
- session id
- overall score
- rubric scores JSON
- summary
- strengths JSON
- weaknesses JSON
- recommendations JSON
- historical comparison JSON
- carry-forward planning signals JSON
- created timestamp
Purpose:
- cache the final review payload
- expose direct planning signals for the next `configure` call
## Planning Logic
Planning behavior to preserve from the prior service:
- use recent completed interview history
- use aggregated recurring weak areas
- let low historical scores and repeated gaps influence question selection
- adjust question emphasis and difficulty based on prior performance
Planning constraints for the rebuild:
- bound history lookup to a small recent window
- summarize recurring weaknesses instead of loading unbounded detail
- keep planning output deterministic enough to inspect and test
- store the history summary actually used during planning
Expected planning artifacts:
- normalized interview configuration
- bounded history summary
- focus areas
- ordered base questions
- opening prompt
- follow-up policy
## Review Logic
Review behavior to preserve:
- score against the retained rubric
- use transcripts together with session audio artifacts
- generate strengths, weaknesses, and recommendations
- compare against prior interviews
- emit carry-forward signals for the next session
Carry-forward planning signals should be explicit and reusable, for example:
- recurring weak areas
- rubric dimensions trending down
- recommended follow-up difficulty
- suggested topic emphasis for the next interview
The review service should persist the finished result once and let `GET /review/{session_id}` return that cached payload directly.
## Audio Archival and S3 Layout
Phase 1 archives both sides of the session, not candidate-only audio.
Recommended S3 object layout:
```text
interviews/{user_id}/{session_id}/session-dual.wav
interviews/{user_id}/{session_id}/session-mixed.mp3
interviews/{user_id}/{session_id}/manifest.json
```
Artifact roles:
- `session-dual.wav` is the canonical review source
- `session-mixed.mp3` is a secondary convenience playback artifact
- `manifest.json` links session metadata, channel mapping, transcript/review references, and artifact properties
Channel mapping:
- channel 1 = assistant
- channel 2 = candidate
Implementation rules:
- assemble artifacts incrementally on disk
- never buffer the full session in memory
- finalize and upload all artifacts on `session.finish`
- persist artifact rows after successful upload with S3 key and metadata
## Runtime Simplification
Keep runtime configuration intentionally small:
- database URL
- Gemini credentials and model
- S3 bucket settings
- review model settings
- temp directory
- history window size
- logging level
Operational decisions for phase 1:
- no Redis
- no SSE
- no external queue or worker process
- no polling orchestration endpoint beyond `GET /review/{session_id}`
- review generation starts as an in-process async task after `session.finish`
If review generation fails, the failure should be stored clearly enough for diagnosis and surfaced predictably through the review endpoint or logs.
## Delivery Sequence
1. Archive the current service as `interview-service-reference`.
2. Scaffold a fresh `interview-service`.
3. Copy only personas, prompts, rubric, and the minimum selected planning/review logic.
4. Create the 4-table schema and initial migration.
5. Implement `POST /configure`.
6. Implement the Gemini Live WebSocket session path.
7. Add ordered turn persistence.
8. Add dual-track archive assembly, mixed export, and manifest generation.
9. Add S3 upload on session completion.
10. Start in-process review generation on `session.finish`.
11. Implement `GET /review/{session_id}`.
12. Validate the rebuilt service against the simplified phase-1 scope.
## Test Plan
The initial test suite should prove the simplified contract end to end.
Core cases:
- `POST /configure` rejects invalid config
- `POST /configure` returns normalized config and history-aware planning output
- historical weak areas alter the next session question plan
- `WS /session/{session_id}` rejects invalid or missing sessions
- turns are persisted in correct sequence order
- assistant and candidate audio are both captured into the archive workflow
- `session-dual.wav`, `session-mixed.mp3`, and `manifest.json` are produced with correct metadata
- S3 upload stores expected keys and artifact rows
- `session.finish` marks the session complete and starts review generation
- `GET /review/{session_id}` returns `processing` before completion and a full payload afterward
- final review includes historical comparison and carry-forward planning signals
- the end-to-end flow works without Redis, SSE, or queue infrastructure
## Acceptance Criteria
The rebuild is ready for phase-1 validation when all of the following are true:
- the service exposes only the 3 required public surfaces
- the archived implementation is preserved separately as `interview-service-reference`
- the new service has only the 4 required database tables
- planning uses bounded historical context and persists the exact planning summary used
- the WebSocket path is Gemini Live only
- both sides of the interview are archived into the canonical dual-track artifact
- artifacts are uploaded to S3 and registered in `interview_artifacts`
- review generation persists rubric-based output plus historical comparison
- the next `configure` call can reuse carry-forward signals directly
- the service runs without Redis, SSE, or external worker infrastructure
## Assumptions and Defaults
- Service name remains `interview-service`.
- The old implementation is preserved only as `interview-service-reference`.
- Audio-only interviewing is the only live mode in phase 1.
- Avatars, screen share, and technical-quality video analysis are deferred.
- Historical context is bounded to a recent window plus aggregated weak-area summaries.
- Review generation runs asynchronously inside the web process.
- `session-dual.wav` is the canonical review artifact.
- `session-mixed.mp3` exists as a convenience artifact, not the source of truth.
## Recommended Next Step
Use this document as the implementation baseline, then create a task-by-task execution checklist in the new `services/interview-service` workspace as soon as the folder archive and scaffold step is complete.

View File

@@ -0,0 +1,338 @@
# GrowQR — Interview Service — Meeting Notes (Decision & Tradeoff Doc)
**Primary purpose:** help the team make high-quality engineering decisions for the Interview Service (and how it composes into the **Upscaling module**: Interview + Roleplay + Courses + Assessment).
**Updated after meeting:** 2026-02-27
**Related cross-service doc:** `growqr/plans/upscaling_redundancy_breakdown.md`
---
## 0) What we learned from the meeting (delta from earlier plan)
### 0.1 Compliance / security baseline is mandatory
You called this “DITA compliant” in the meeting. Im interpreting that as: **baseline privacy + security controls suitable for US/EU/India markets** (not full SOC2-from-day-1, but not a hobby project).
### 0.2 Timeline changed
- Previous assumption: ~67 working days
- New agreed direction: **~3 weeks** so we can optimize latency, consistency, and security properly.
### 0.3 Latency is now a core requirement
We need the experience to be:
- fast to interact
- seamless (no awkward waits)
- less robotic (voice prosody + conversational pacing)
This affects where we put STT/TTS/avatar/lip-sync (client vs server) and whether we do streaming.
### 0.4 Client vs server split was debated
- Team leaned server-side for “control”
- You argued client-side for **cost, scalability, compliance, and lower infra**
- Current direction: **client-heavy media + near-real-time text to server** (recommended compromise)
---
## 1) Baseline compliance & security checklist (US/EU/India)
### 1.1 What we should implement in v1 (minimum)
- **TLS everywhere**
- **Encryption at rest** (DB + object storage; KMS-managed keys where possible)
- **Least privilege IAM** (per-service roles; scoped permissions)
- **Presigned URLs** for uploads/downloads (short expiry; scoped paths)
- **PII minimization**: explicitly classify data
- Tier A: account identifiers
- Tier B: transcripts (sensitive)
- Tier C: raw recordings (highly sensitive)
- Tier D: derived metrics (lower sensitivity)
- **Retention controls**: configurable retention for recordings and transcripts
- **Deletion workflow**: delete user data on request; delete expired artifacts automatically
- **Access audit logs**: log access to raw recordings and reports
- **Vendor DPAs** (if using paid AI providers): confirm acceptable processing + region
### 1.2 Security guardrails that improve decision-making
- Prefer **client-side processing** for sensitive media where possible.
- If we must use paid providers, prefer:
- providers that support enterprise controls and DPAs
- region pinning/data residency where required
---
## 2) What is a “real-time streaming pipeline” (and what we actually need)
A real-time streaming pipeline processes data continuously while its produced.
### Level 0 — Batch (simplest)
- Record → upload → analyze.
- Low engineering risk, high latency.
### Level 1 — Near-real-time (recommended)
- Client produces transcript quickly and sends **text turn** immediately.
- Server generates next question immediately (optionally with **token streaming**).
- Media uploads continue in background and are used for **post-session analysis**.
### Level 2 — True streaming (complex/expensive)
- Stream audio/video to server (WebRTC/WebSocket)
- Streaming STT → streaming LLM → streaming TTS
- Maximum complexity, maximum compliance surface area.
**Recommendation:** Level 1. It achieves “fast and seamless” without heavy streaming of user audio/video.
---
## 3) Optimal client vs server split (for cost, latency, and compliance)
### 3.1 Client-side (recommended)
These reduce backend infra cost and reduce compliance risk.
1) **Media capture + encoding**
- camera/mic recording
- screen share (specific window)
- local compression
2) **STT (speech-to-text) where feasible**
- produce transcript locally and send text; enables fast turn-taking
3) **TTS (text-to-speech) for AI persona**
- fast, avoids voice vendor calls; BUT voice quality can vary across devices
4) **Avatar rendering + lip sync**
- best in client renderer (2D/3D) for low latency
- accuracy improves if we can get **viseme/phoneme timing** from TTS
5) **Optional CV feature extraction**
- MediaPipe landmarks → send compact features/metrics rather than raw frames
### 3.2 Server-side (should remain centralized)
1) **Session orchestration + persistence**
- state machine, timing, idempotency
2) **Question selection/generation**
- interview type logic, persona rules
3) **Scoring + report generation**
- deterministic numeric scoring
- LLM-generated narrative sections (structured)
4) **Artifact registry + storage broker**
- presigned URLs, metadata, retention/deletion
5) **History/trends**
6) **Integrations**
- emit results to Dashboard/Courses/Assessment/Roleplay
---
## 4) On-device models (browser): realistic options
You mentioned bundling “a small whisper model for TTS” — Whisper is **STT**, not TTS.
### 4.1 STT client options
- **Fastest (low engineering):** Web Speech Recognition
- **Self-contained:** `whisper.cpp` / WASM Whisper (tiny/base)
- Pros: privacy + no vendor
- Cons: model download size + CPU cost
- **Hybrid fallback:** try local STT; if unavailable/slow, user opts-in to server STT
### 4.2 TTS client options
- **Simple:** Web Speech Synthesis / native OS voices
- **Higher quality + lip sync friendly (paid):** Azure Speech TTS (supports visemes)
- Note: only the assistant text is sent; user audio/video still stays client-side
### 4.3 Lip sync options (for “not robotic”)
- **Best for latency:** client-rendered avatar + viseme timing (from TTS or heuristic)
- **Worst for latency:** pre-rendered avatar videos per utterance (often seconds delay)
---
## 5) Modules required (composition modules)
1) API layer (HTTP)
2) AuthN/AuthZ verification
3) Session State Machine & Orchestrator
4) Question Bank + Rubrics
5) Turn ingestion (Q/A turns)
6) Media broker (presigned URLs, metadata)
7) Background jobs (analysis worker)
8) Signal processing (optional)
9) Scoring engine (deterministic)
10) Report generator (structured feedback)
11) History/trends
12) Outbound integrations (events/webhooks + outbox)
13) Observability
14) Compliance controls (retention/deletion/audit)
---
## 6) Implementation options per module (OSS vs Paid vs Paid-simple)
**Legend**
- **OSS** = self-hostable
- **Paid** = best quality / flexible
- **Paid-simple** = easiest integration / fewest moving parts
### 6.1 API layer
- OSS: FastAPI / NestJS
- Paid: AWS API Gateway
- Paid-simple: Cloudflare Workers
**Decision (LOCKED):** **FastAPI**
### 6.2 Database
- OSS: Postgres self-host
- Paid: RDS/Cloud SQL
- Paid-simple: Supabase Postgres
**Decision (LOCKED):** **Self-hosted Postgres** (on GCP/compute)
### 6.3 Storage
- OSS: MinIO
- Paid: S3 / GCS
- Paid-simple: Cloudflare R2
**Decision (LOCKED):** **Google Cloud Storage (GCS)** (S3-compatible bucket)
### 6.4 Jobs/queue
- OSS: RQ/Celery + Redis
- Paid: SQS + ECS/Lambda
- Paid-simple: Step Functions
**Decision (LOCKED):** **RQ + Redis** (built into the service)
### 6.5 LLM (questions + report narrative)
- OSS: Ollama / vLLM
- Paid: OpenAI / Anthropic / Gemini
- Paid-simple: single-provider adapter
**Decision (LOCKED):** **OpenRouter / OpenAI key** (via an adapter)
### 6.6 STT
- OSS: faster-whisper (server) / whisper.cpp WASM (client)
- Paid: Deepgram / AssemblyAI / Google STT
- Paid-simple: AWS Transcribe
**Decision (LOCKED):** **Whisper WASM** on the client side
### 6.7 TTS
- OSS: Piper / Coqui
- Paid: ElevenLabs / Azure Speech
- Paid-simple: native/browser TTS
**Decision (LOCKED):** **Google Cloud TTS** (we have an account, simple integration)
### 6.8 Facial/body/technical quality
- OSS: MediaPipe client or server
- Paid: Rekognition/Azure Face
- Paid-simple: client-only metrics
**Decision (LOCKED):** **MediaPipe on the client** (no AWS Rekognition)
### 6.9 Screen-share / coding analysis
- OSS: structured artifacts + tree-sitter
- Paid: LLM code feedback; optional sandbox
- Paid-simple: LLM-only feedback from code text
**Decision (LOCKED):** **Simple feedback only** for now (no heavy OCR/analysis)
---
## 7) Two best-path approaches
### Option A — Client-heavy + Paid AI (recommended)
- Client: capture + encode + (STT/TTS/avatar/lip-sync)
- Server: orchestration + scoring + report + history + compliance + integrations
- Paid LLM for narrative + follow-ups
**Pros:** best speed-to-quality tradeoff, minimal infra, easier compliance.
**Cons:** variable LLM cost; requires careful client contract.
### Option B — OSS/self-hosted ML
- Self-host LLM + STT + TTS + CV
**Pros:** maximum control, lower marginal cost at scale.
**Cons:** GPU ops + longer timeline.
---
## 8) Tradeoffs (Paid vs OSS)
| Dimension | Client-heavy + Paid AI | OSS-first |
|---|---|---|
| Time-to-ship | Best | Slower |
| Latency UX | Best (if we stream text + client TTS) | Depends on infra |
| Compliance surface | Smaller (less user media sent) | Smallest if fully local |
| Ops burden | Low | High |
| Cost profile | Usage-based | Fixed infra + ops |
---
## 9) Timeline estimate (updated)
### 9.1 Recommended plan — **~3 weeks**
**Week 1: foundations + compliance**
- finalize client/server contract
- DB schema + migrations
- state machine
- artifact broker (presigned URLs)
- retention + deletion hooks + audit logging
**Week 2: latency + interaction path**
- “fast path” transcript turn-taking
- SSE streaming responses (if using LLM)
- deterministic scoring engine + report generator v1
- background worker pipeline
**Week 3: reliability + integrations + polish**
- idempotency, retries, outbox
- perf budget enforcement (≤60s analysis)
- events to Dashboard/Courses/Assessment/Roleplay
- security review checklist + load test
### 9.2 If we insist on true server-side streaming (Level 2)
Add **+3 to +6 weeks** (complexity explodes: streaming STT/TTS, infra, compliance).
---
## 10) Cost model (decision-friendly, not exact pricing)
### 10.1 What costs money
- LLM tokens (follow-ups + narrative report)
- STT minutes (if server-side fallback)
- TTS characters (if server-side paid voices)
- storage (video/audio/screen)
- compute for workers
### 10.2 Cheapest sustainable shape
- Keep user audio/video processing **client-side**
- Send only **text turns** to server for interaction
- Upload media in background for post-analysis (or make recording storage opt-in)
### 10.3 “Buy vs build” money tradeoff (qualitative)
- Buying LLM/STT/TTS reduces engineering and ops cost immediately, but increases variable cost.
- OSS reduces variable cost at scale, but increases:
- GPU infra costs
- reliability/monitoring burden
- engineering time
---
## 11) Cross-service redundancy note
Interview/Roleplay/Courses/Assessment share platform concerns (credits, artifacts, certificates, events, skill taxonomy, compliance).
See: `growqr/plans/upscaling_redundancy_breakdown.md`
---
## 12) Open questions (need answers to lock implementation)
1) When we say “DITA compliant”, confirm the target:
- baseline GDPR/DPDP/CCPA + security controls?
- or a specific internal standard?
2) Do we store raw recordings by default or make it opt-in with retention caps?
3) For “less robotic voice”: do we accept platform TTS variance, or require consistent paid TTS (Azure Speech, etc.)?
4) Client STT: commit to WASM Whisper now, or as a progressive enhancement/fallback?

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,198 @@
# GrowQR — Upscaling Module — Redundancy vs Unique Work (Interview / Roleplay / Courses / Assessment)
**Purpose:** break down the 4 services in the Upscaling module, identify **redundant modules** we should share/standardize, and clarify **what is unique** per service.
**Inputs reviewed (in `growqr/plans/`):**
- `interview service plan.md`
- `Roleplay_OnePager.docx`
- `Course_OnePager.docx`
- `Assessment_OnePager.docx`
---
## 1) Upscaling module: services and their primary job
1) **Interview Service**
- Real-time-ish interview practice, persona-driven Q/A
- Records user media + optional screen share
- Outputs 7-metric coaching + historical comparison
2) **Roleplay Service**
- Avatar-based AI roleplay (video/voice) + optional screen share
- Heavier focus on avatar, lip-sync, emotional expression
- Outputs weighted performance scoring + certificates for scenario thresholds
3) **Courses Service**
- Course catalog + external provider integrations
- Enrollment/progress tracking + certificates
- Recommendation engine consumes gaps from other services
4) **Assessment Service**
- Multi-stakeholder assessment marketplace
- Upload-first (CSV/JSON/Excel), AI-generated assessments as secondary
- Psychometric/behavioral data feeds the global recommendation engine
---
## 2) Redundant modules (should be shared or standardized)
### 2.1 Identity / auth verification
All services require:
- verify user identity
- enforce org visibility (marketplace vs private library)
**Recommendation:** standard auth library / gateway policy + shared middleware.
### 2.2 Credits / entitlements
All services deduct credits:
- Interview: duration tier → credits
- Roleplay: per session
- Courses: per course type
- Assessment: possibly per attempt / premium
**Recommendation:** one central Credits/Entitlements service or shared library + consistent idempotent “deduct” contract.
### 2.3 Artifact storage + media broker
Interview/Roleplay generate large artifacts (video/audio/screen). Courses/Assessments generate smaller artifacts (certificates, uploads).
Shared needs:
- presigned upload/download
- artifact metadata registry
- retention policy and deletion
**Recommendation:** shared “Artifact Registry” module/service (even if storage is per-service).
### 2.4 Certificate generation
Courses, Assessments, Roleplay (and potentially Interview) all generate certificates.
Shared needs:
- template engine
- signing/verification
- storage + download links
**Recommendation:** shared Certificate service/library.
### 2.5 Eventing + outbox pattern
All services share data with each other and Dashboard.
Shared needs:
- event schema versioning
- retries, idempotency
**Recommendation:** standard event format + outbox implementation that every service uses.
### 2.6 Skill taxonomy + skill-gap representation
Recommendations depend on consistent “skills” and “gaps” representation.
Shared needs:
- canonical skill IDs
- mapping metrics → skills
**Recommendation:** define a shared Skill Taxonomy and a `SkillGap` schema used by all services.
### 2.7 Recommendation engine inputs/outputs
Courses are recommended based on:
- Interview weaknesses
- Roleplay weaknesses
- Assessment topic gaps + psychometrics
Shared needs:
- consistent “signals” API (what each service emits)
**Recommendation:** a shared “Recommendation Signals” contract:
- `SignalProduced(service, userId, signalType, payload, timestamp, version)`
### 2.8 Compliance baseline (US/EU/India)
All services must support:
- PII minimization
- retention controls
- deletion workflows
- access auditing
**Recommendation:** shared compliance checklist + shared primitives (retention tags, audit log schema).
---
## 3) Unique modules (must be built per service)
### 3.1 Interview Service — unique work
- persona-driven interview state machine
- question bank and follow-up generation
- 7-metric interview-specific scoring weights
- historical comparison optimized for interview metrics
### 3.2 Roleplay Service — unique work
- avatar rendering integration strategy (real-time avatar vs pre-rendered video)
- voice synthesis + lip-sync quality targets (≤100ms target mentioned)
- scenario configuration and scenario-specific certificate rules
- roleplay-specific weights (Voice 35%, Facial 25%, Body 20%, Technical 10%, Content 10%)
### 3.3 Courses Service — unique work
- external provider integrations and progress sync/webhooks
- catalog ingestion + caching strategy
- enrollment state machine (in progress/completed/abandoned)
### 3.4 Assessment Service — unique work
- multi-stakeholder creator workflows
- bulk upload parsing + validation
- flexible data collection schema per creator
- timer/navigation engine
- creator analytics dashboards + exports
- psychometric/behavioral modeling signals
---
## 4) Where client-side vs server-side makes sense (cross-service)
### For Interview + Roleplay (real-time experiences)
**Client-side is optimal for:**
- recording + encoding
- optional local STT (for fast turn-taking)
- avatar rendering + lip sync
- optional MediaPipe feature extraction
**Server-side is optimal for:**
- session orchestration + credits
- question generation
- post-session scoring + report
- artifacts registry + retention/audit
### For Courses + Assessment
Mostly server-side:
- workflows are CRUD + marketplace + sync
- no need for client-side heavy ML
---
## 5) Recommended shared platform building blocks (minimal)
If we want “shared but not over-engineered”, build these as either shared libraries or small internal services:
1) **Credits/Entitlements** (idempotent deduction API)
2) **Artifact Registry** (metadata + presigned URL patterns)
3) **Certificates** (template + signing)
4) **Event schemas + outbox** (reliable cross-service sharing)
5) **Skill taxonomy + SkillGap schema** (powering recommendations)
6) **Compliance primitives** (retention tags, deletion requests, audit events)
---
## 6) Quick risk notes
- If Interview and Roleplay choose different avatar/TTS strategies, they can still share:
- the session + artifacts + scoring/report patterns
- the eventing + skill gap outputs
- If we attempt server-side real-time audio/video streaming early, we significantly increase:
- cost
- compliance surface area
- time-to-ship
---
## 7) Next planning step
Decide and document:
1) The **shared contracts** (Credits, Artifacts, Events, SkillGap)
2) The **client/server contract** for Interview + Roleplay (what must client compute vs server)
3) The **retention + deletion policy** for recordings across markets

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,335 @@
**GrowQR**
**COURSE SERVICE**
Business Requirements Document • v2.0 • March 2026
| Upskilling Module • Microservice Specification Three-Phase Courseware Strategy • No Proprietary LMS |
| :---: |
| Document Title | Course Service — Business Requirements Document |
| :---- | :---- |
| Service Type | Standalone Microservice (Part of Upskilling Services) |
| :---- | :---- |
| Version | |
| :---- | :---- |
| Integration | Shares data with Roleplay, Interview, Assessment, Pathways \+ Dashboard |
| :---- | :---- |
| Courseware Strategy | Three-phase: External Index → Third-Party Creator → GenAI IP Generation |
| :---- | :---- |
| LMS Approach | No proprietary LMS. Integrates with Coursera, Moodle, Thinkific and others |
| :---- | :---- |
| 1\. SERVICE OVERVIEW |
| :---- |
The Course Service provides a curated learning library with external provider integrations and community-created content. Users enroll using credits, track progress, and earn certificates upon completion. GrowQR does not build a proprietary LMS — all courseware delivery relies on third-party platforms and a three-phase strategy to progressively own intellectual property.
## **1.1 Core Features**
• Three-phase courseware strategy: External mapping → Third-party creation → GenAI IP generation
• No proprietary LMS: Integration with Coursera, Moodle, Thinkific, LinkedIn Learning
• Course catalog with external provider integrations and community scenarios
• AI-powered recommendations based on skill gaps from Assessment, Interview, Roleplay, Q-Score
• Credit-based enrolment tracking: In Progress / Completed / Abandoned
• Certificate generation upon course completion (eligible courses only)
• Persona-driven content mapping across 2025 unique user profiles, industries, and life stages
| 2\. THREE-PHASE COURSEWARE STRATEGY |
| :---- |
The courseware strategy follows a deliberate, staged approach that builds toward platform intellectual property (IP) through GenAI-generated, persona-driven content. Each phase unlocks the next.
| PHASE 1: External Mapping & Indexing |
| :---- |
| • Map user personas to purchased or indexed external courses (e.g., Coursera, LinkedIn Learning, Udemy) |
| • Users browse a curated catalog; GrowQR surfaces the most relevant content per role, industry, and Q-Score gap |
| • Course metadata indexed: title, provider, duration, difficulty, skills covered, rating, price |
| • AI recommendation engine selects top matches from external catalog based on skill gap analysis |
| • Revenue model: Affiliate commissions from enrolled courses via provider APIs |
| • No content creation required — pure aggregation and curation layer |
| PHASE 2: Third-Party Creator Platform |
| :---- |
| • Platform opens to third parties: Heads of Departments (HODs), corporates, and subject matter experts |
| • Creators bundle and publish their own content within the GrowQR platform |
| • Content types: Video modules, guided projects, assessments, case studies |
| • GrowQR provides creator tools, hosting (via Moodle / Thinkific integration), and distribution |
| • Revenue model: Revenue share with creators; premium access tiers for corporate bundles |
| • Quality control: Community ratings, completion rates, and AI-driven content scoring |
| • Enables industry-specific content that external platforms do not cover |
| PHASE 3: GenAI IP Generation (Intellectual Property) |
| :---- |
| • Full-blown personalised course generation using Generative AI |
| • Content defined by 2025 unique user personas, mapped to industry, role, and life stage |
| • Each persona receives a structured, distinct learning path — not just filtered external content |
| • GrowQR owns this content as platform IP: structured curricula, assessments, and roleplay scenarios |
| • Life stage mapping: College student → First job → Career pivot → Leadership → Entrepreneurship |
| • Industry mapping: Tech, Finance, Healthcare, Marketing, Operations, Creative, etc. |
| • GenAI generates course scripts, quizzes, scenario prompts, and practice exercises on demand |
| • This phase creates the long-term competitive moat and differentiated platform identity |
| 3\. FUNCTIONS |
| :---- |
## **FUNCTION 1: Course Discovery & Catalog**
**3.1.1 Course Sources (by Phase)**
| Phase | Source | Description |
| :---- | :---- | :---- |
| Phase 1 | Coursera, LinkedIn Learning, Udemy, edX | Externally indexed courses mapped to user personas and Q-Score gaps |
| Phase 1 | Internal Fallback / Question Bank | GrowQR-curated content when external APIs are unavailable |
| Phase 2 | HODs, Corporates, Subject Matter Experts | Third-party content created and hosted via Moodle / Thinkific |
| Phase 2 | Community Scenarios | User-generated learning content, peer-reviewed and rated |
| Phase 3 | GenAI Generated (GrowQR IP) | Fully personalised courses generated from 2025 user personas by GenAI |
**3.1.2 Persona Mapping (Phase 3 Foundation)**
Course content is structured around 2025 distinct user personas. Each persona is defined by the intersection of:
• Role category (e.g., Software Engineer, Product Manager, Sales Leader)
• Industry (e.g., FinTech, Healthcare, E-commerce, SaaS)
• Life stage (e.g., College student, Early career, Career pivot, Leadership track, Entrepreneur)
• Q-Score profile (which of the 25 Q-Scores are high, low, or developing)
• Motivation archetype (Technical Specialist, Strategic Leader, Creative Innovator, etc.)
**3.1.3 Data Requirements**
| Field | Description |
| :---- | :---- |
| Course ID | Unique identifier |
| Title | Course name |
| Provider | Coursera, LinkedIn Learning, Moodle, Thinkific, GrowQR IP, etc. |
| Phase | 1 (External) / 2 (Third-Party) / 3 (GenAI IP) |
| Type | Full Course / Guided Project / Micro-module |
| Persona Tags | Array of persona IDs this course maps to |
| Q-Score Tags | Which Q-Scores this course develops |
| Life Stage | College / Early Career / Pivot / Leadership / Entrepreneur |
| Duration | Estimated time to complete |
| Difficulty | Beginner / Intermediate / Advanced |
| Certificate Available | Boolean — awards certificate on completion? |
| Credit Cost | Free (1 credit) / Guided Project (2 credits) / Full Course (3 credits) |
## **FUNCTION 2: Course Enrolment**
**3.2.1 Enrolment Flow**
1\. User selects course → System checks: credits available, not already enrolled
2\. Credit deducted based on course type
3\. Enrolment record created: User ID, Course ID, Start date, Phase, Status (In Progress)
4\. External courses: Redirect to provider platform with tracking link
5\. Phase 3 / Internal courses: Delivered natively within GrowQR
**3.2.2 Credit Costs**
• Free courses: 1 credit to enrol
• Guided Projects: 2 credits
• Full Courses: 3 credits
• GenAI IP courses (Phase 3): Credit cost TBD based on persona depth
## **FUNCTION 3: Progress Tracking & Certificates**
• Track enrolment status: In Progress / Completed / Abandoned
• External courses (Phase 1): Webhook from provider OR periodic sync
• Third-party courses (Phase 2): Progress tracked via Moodle / Thinkific integration
• GenAI IP courses (Phase 3): Module-level completion tracked natively
• Certificate issued when: Course completed AND Certificate Available \= true
• Certificate includes: User name, Course title, Provider/Phase, Completion date, Certificate ID
## **FUNCTION 4: AI-Powered Recommendations**
**3.4.1 Recommendation Logic**
• Analyse data from Assessment, Interview, and Roleplay services
• Identify Q-Score gaps and map to relevant course tags
• Cross-reference user persona profile (role, industry, life stage, archetype)
• Prioritise: Highest-rated courses, best persona match, free courses first
• Phase 3 courses prioritised for users with established Q-Score histories
**3.4.2 Data Inputs**
• Assessment results: Low-scoring topics and Q-Score contributions
• Interview feedback: Weak areas identified
• Roleplay performance: Scenarios user struggles with
• User profile: Career goals, current role, life stage, archetype
• Pathway data: Current week in cycle and progression phase (Learn vs. Apply ratio)
| 4\. DATA SHARING WITH OTHER SERVICES |
| :---- |
| Target Service | Data Shared | Purpose |
| :---- | :---- | :---- |
| Assessment Service | Courses completed, topics learned | Re-test user on completed course topics to show improvement |
| Interview Service | Course completion, skills learned | Tailor interview questions to validate learning |
| Roleplay Service | Course completion, skills practiced | Suggest roleplay scenarios for learned skills |
| Pathways Service | Enrolment count, completed courses, Q-Score signals | Adjust weekly cycle priorities and learning/apply ratio |
| Dashboard Service | Enrolment count, completed courses, certificates earned | Update Q-Score, display achievements and progress |
| Job Matchmaking | Skills learned, certifications, course completion signals | Improve opportunity match quality and relevance |
| 5\. TECHNICAL REQUIREMENTS |
| :---- |
## **5.1 External API Integrations**
| Provider | Phase | Integration Method |
| :---- | :---- | :---- |
| Coursera | Phase 1 | Coursera Catalog API \+ affiliate tracking |
| LinkedIn Learning | Phase 1 | LinkedIn Learning API |
| Udemy | Phase 1 | Udemy Affiliate API |
| edX | Phase 1 | edX API |
| Moodle | Phase 2 | Moodle REST API \+ Webhook for completion tracking |
| Thinkific | Phase 2 | Thinkific API \+ Embed for third-party creator content |
| GrowQR GenAI | Phase 3 | Internal LLM pipeline — on-demand course generation |
## **5.2 Performance Requirements**
| Operation | Target SLA |
| :---- | :---- |
| Course catalog load | \< 2 seconds |
| Enrolment processing | \< 1 second (after credit check) |
| AI course recommendation | \< 2 seconds |
| Certificate generation | \< 3 seconds after completion |
| External provider sync (Phase 1\) | \< 5 seconds |
| Moodle / Thinkific sync (Phase 2\) | \< 10 seconds |
| GenAI course generation (Phase 3\) | \< 30 seconds for full micro-module |
| 6\. ACCEPTANCE CRITERIA |
| :---- |
| \# | Must Pass | Pass / Fail |
| :---- | :---- | :---- |
| **1** | Phase 1: All courses load from external APIs (Coursera, Udemy, LinkedIn Learning). Filters and persona mapping work. | \[ \] PASS \[ \] FAIL |
| **2** | Phase 2: Moodle and Thinkific integrations functional. Third-party creators can publish and bundle content. | \[ \] PASS \[ \] FAIL |
| **3** | Phase 3: GenAI generates structured micro-courses for at least 5 validated personas. Content is unique and role-specific. | \[ \] PASS \[ \] FAIL |
| **4** | Credits deducted correctly on enrolment. Enrolment record created. External redirect works. | \[ \] PASS \[ \] FAIL |
| **5** | Progress status updates correctly for all three phases. External sync works or shows last known state. | \[ \] PASS \[ \] FAIL |
| **6** | Certificates generated for eligible completed courses. Download link works. | \[ \] PASS \[ \] FAIL |
| **7** | AI recommends relevant courses based on Q-Score gaps, persona profile, and pathway cycle phase. | \[ \] PASS \[ \] FAIL |
| **8** | Completion data and Q-Score signals shared with all connected services. Dashboard receives course count. | \[ \] PASS \[ \] FAIL |
| **9** | Persona mapping covers minimum 20 distinct profiles across role, industry, and life stage dimensions. | \[ \] PASS \[ \] FAIL |
| **10** | Pathway integration: Course recommendations align with current weeks learn/apply ratio in the weekly cycle. | \[ \] PASS \[ \] FAIL |

View File

@@ -0,0 +1,76 @@
| GrowQR Interview Service — One-Pager Avatar-Based AI Interviewers \+ Video/Voice \+ Screen Share | v3 | INTERVIEW |
| :---- | :---: |
| PURPOSE |
| ----- |
| AI-powered mock interviews with 4 avatar-based interviewers (Payal, Emma, John, Kapil) that speak using real-time voice synthesis. Users recorded via video/audio and can share screen for coding tests/technical demos. Comprehensive analysis across 6 metrics (Intro, Facial Expression, Body Language, Language, Voice including filler word count, Outro) \+ Technical Quality (lighting, framing, background, audio). Historical comparison tracks improvement over time. |
| CORE FEATURES | |
| :---: | :---- |
| **1** | 4 AI Interviewer Avatars: Payal (warm, friendly), Emma (professional, structured), John (authoritative, challenging), Kapil (casual, conversational) \- each with distinct voice |
| **2** | Real-Time Voice Synthesis: AI interviewers SPEAK all questions with personality-matched voices and natural intonation |
| **3** | Interview Types: Warm Up (Non-technical), Coding (Programming), Role-Related (Technical), Behavioral (HR) |
| **4** | Duration Tiers: 5 mins (1 credit), 15 mins (2 credits \- Premium), 30 mins (3 credits \- Premium) |
| **5** | Screen Share: User shares specific window for coding tests, technical demos, presentations |
| **6** | 7-Metric Analysis: Intro (10%), Facial Expression (20%), Body Language (20%), Language (15%), Voice (20% \- includes filler word count), Outro (10%), Technical Quality (5%) |
| **7** | Historical Comparison: Track improvement across multiple interviews with trend analysis |
| USER JOURNEY | | | |
| :---: | ----- | ----- | ----- |
| **Step** | **User Action** | **System Response** | **Data Captured** |
| **1** | User configures interview | Validate: type, duration, persona, credits | Config parameters |
| **2** | User starts interview | Deduct credits, load avatar, request permissions | Session ID, Credits deducted |
| **3** | Avatar speaks greeting | Voice synthesis: "Hello\! I'm your AI interviewer..." | Timer starts, Recording begins |
| **4** | User shares screen (optional) | Capture window, start screen analysis | Screen recording, Window type |
| **5** | Avatar speaks question | Voice synthesis with lip-sync | Question logged |
| **6** | User responds (voice/text) | Capture video/audio, analyze filler words, process screen | Transcript, Filler count, Technical quality, Screen |
| **7** | Session ends | Stop recordings, trigger analysis | End time, Completion status |
| **8** | Analysis completes | Calculate 7 metrics, compare to history | All metric scores \+ historical comparison |
| KEY STATES TO HANDLE | | |
| ----- | ----- | ----- |
| **State** | **Condition** | **System Behavior** |
| **Permission Denied** | User blocks camera/mic | Error: 'Camera/mic required. Screen share optional for coding.' |
| **Avatar Loading** | Persona initializing | Show: 'Preparing interview with \[Name\]...' (5-10s) |
| **Active Interview** | Session in progress | Avatar speaks, user responds, timer running |
| **Screen Share Active** | User sharing window | Screen content captured and analyzed |
| **AI Service Error** | AI unavailable | Show error, use fallback questions |
| **Voice Synthesis Error** | TTS fails | Fallback: text bubbles |
| **Analysis Processing** | Calculating metrics | Show: 'Analyzing...' (30-60s) |
| **Results Ready** | Analysis complete | Display 7 metrics \+ screen \+ historical \+ recommendations |
| ANALYSIS METRICS | |
| ----- | ----- |
| **Metric** | **What's Analyzed** |
| **Intro (10%)** | Opening greeting quality, confidence, first impression, professionalism |
| **Facial Expression (20%)** | Engagement, authenticity, eye contact, smile appropriateness, emotional state |
| **Body Language (20%)** | Posture, Gestures, Professionalism, Fidgeting, Movement patterns |
| **Language (15%)** | Grammar, Vocabulary, Clarity, Sentence structure, Articulation |
| **Voice (20%)** | Tone, Pace (WPM), Volume, Filler words COUNT (um, uh, like, you know), Vocal confidence |
| **Outro (10%)** | Closing statement, Questions to interviewer, Professionalism, Final impression |
| **Technical Quality (5%)** | Lighting: Well-lit/Poor | Framing: Centered/Off | Background: Professional/Distracting | Audio: Clear/Noisy |
| **Screen Content** | Code: Syntax, Structure, Logic | Presentations: Quality, Clarity | Demos: Completeness |
| DATA SHARING WITH OTHER SERVICES | | |
| ----- | ----- | ----- |
| **Target Service** | **Data Shared** | **Purpose** |
| **Roleplay Service** | Communication gaps, weak types, low scores, filler patterns | Suggest roleplay scenarios for weak areas |
| **Assessment Service** | Technical gaps, low topics, code quality issues | Recommend assessments for validation |
| **Course Service** | Skill gaps, low metrics, coding weaknesses | Recommend courses (interview prep, communication, technical) |
| **Dashboard Service** | Interview count, scores across 7 metrics, trends, code analysis | Update Q-Score, show progress, achievements |
| ACCEPTANCE CRITERIA | | |
| :---: | ----- | :---: |
| **\#** | **Must Pass** | **Pass/Fail** |
| **1** | All 4 personas render correctly. Voice synthesis works with distinct voices and lip-sync. | \[ \] PASS \[ \] FAIL |
| **2** | All interview types selectable. Premium durations tier-gated with upgrade prompts. | \[ \] PASS \[ \] FAIL |
| **3** | Video/audio captured throughout. Stored in cloud. Download links work. | \[ \] PASS \[ \] FAIL |
| **4** | User can share specific window. Screen recording works. Can stop/resume sharing. | \[ \] PASS \[ \] FAIL |
| **5** | AI analyzes voice with filler word COUNT. Count displayed in feedback. | \[ \] PASS \[ \] FAIL |
| **6** | AI analyzes technical quality: Lighting, Framing, Background, Audio. Ratings displayed. | \[ \] PASS \[ \] FAIL |
| **7** | AI analyzes screen content: Code quality, Presentation quality, Demo completeness. | \[ \] PASS \[ \] FAIL |
| **8** | All 7 metrics calculated correctly. Analysis completes within 60s. | \[ \] PASS \[ \] FAIL |
| **9** | Historical comparison works: Shows previous scores with dates vs current. Includes all metrics. | \[ \] PASS \[ \] FAIL |

View File

@@ -0,0 +1,71 @@
| GrowQR Roleplay Service — One-Pager Avatar-Based AI \+ Real-Time Video/Voice \+ Screen Share | v3 | ROLEPLAY |
| :---- | :---: |
| PURPOSE |
| ----- |
| Avatar-based AI roleplay with real-time video/audio/screen interaction. AI personas speak using voice synthesis. Users respond via voice/text and can share screen (specific window) for coding/presentation demos. System analyzes voice (including filler word count), facial expressions, body language, technical setup quality (lighting, framing), and screen content to provide comprehensive performance feedback and certificates. |
| CORE FEATURES | |
| :---: | :---- |
| **1** | Avatar-Based AI Personas: Visual characters with voice synthesis, lip-sync, emotional expressions |
| **2** | Real-Time Voice Synthesis: AI persona SPEAKS all questions and responses (not just text bubbles) |
| **3** | Video/Audio Recording: Capture user's camera and microphone throughout entire session |
| **4** | Screen Share: User shares specific window (IDE, slides, demo app) \- NOT full desktop |
| **5** | AI Screen Content Analysis: Analyzes code quality (syntax, logic), presentation slides, demos |
| **6** | Comprehensive Analysis: Voice (tone, pace, filler word count), Facial (engagement, eye contact), Body (posture, gestures), Technical Quality (lighting, framing, background), Screen content |
| **7** | Performance Scoring: Voice 35%, Facial 25%, Body Language 20%, Technical Quality 10%, Content 10% |
| USER JOURNEY | | | |
| :---: | ----- | ----- | ----- |
| **Step** | **User Action** | **System Response** | **Data Captured** |
| **1** | User selects scenario | Load AI persona avatar, request camera/mic/screen permissions | Scenario ID, User ID |
| **2** | Permissions granted | Initialize avatar rendering, voice synthesis, recording systems | Media access granted |
| **3** | Session starts | Deduct 1 credit, start all recording (video/audio/screen), avatar speaks first question | Session ID, Start time, Recording streams |
| **4** | User shares screen (optional) | Capture specific window, begin screen content analysis | Screen recording, Content type detected |
| **5** | User responds (voice/text) | Capture response, AI analyzes voice/facial/body/technical/screen in real-time or queued | Transcript, Voice metrics (including filler count), Facial timeline, Body timeline, Technical quality (lighting/framing), Screen analysis |
| **6** | AI persona responds | Voice synthesis speaks follow-up, avatar lip-syncs | Conversation flow |
| **7** | Session completes | Stop all recordings, finalize analysis, calculate scores across all metrics | Overall score, Voice 88%, Facial 75%, Body 82%, Technical 90%, Screen 85% |
| KEY STATES TO HANDLE | | |
| ----- | ----- | ----- |
| **State** | **Condition** | **System Behavior** |
| **Permission Denied** | User blocks camera/mic/screen | Show error: 'Camera, microphone required. Screen share optional but recommended.' |
| **Media Loading** | Avatar/voice/recording initializing | Show: 'Preparing your session...' with progress (5-10s) |
| **Connection Unstable** | Poor network, dropped frames/audio | Degrade quality or switch to text-only mode, continue session |
| **Voice Synthesis Error** | TTS service fails | Fallback: Display text bubbles instead of speaking, avatar remains visible |
| **Screen Share Stopped** | User stops sharing mid-session | Continue session without screen analysis, note in results |
| **Active Session** | Roleplay in progress | Avatar speaks, user responds, all recording/analysis systems active |
| **Analysis Complete** | Post-session processing done | Display all scores: Voice, Facial, Body Language, Technical Quality, Screen Content (if shared), Overall |
| ANALYSIS METRICS | |
| ----- | ----- |
| **Metric** | **What's Analyzed** |
| **Voice (35%)** | Tone (friendly/professional), Pace (WPM), Clarity (articulation), Confidence (vocal strength), Filler words COUNT (um, uh, like, you know) |
| **Facial Expression (25%)** | Smile frequency, Eye contact (camera gaze), Emotional state (neutral/happy/stressed), Engagement level |
| **Body Language (20%)** | Posture (upright/slouched), Gestures (open/closed), Fidgeting, Professionalism rating |
| **Technical Quality (10%)** | Lighting: Well-lit/Acceptable/Poor | Framing: Centered in frame/Off-center | Background: Professional/Neutral/Distracting | Audio quality: Clear/Background noise |
| **Content Quality (10%)** | Relevance, Completeness, Accuracy of responses |
| **Screen Content (if shared)** | Code: Syntax, structure, logic, best practices | Presentations: Slide design, clarity | Demos: Feature completeness, explanation quality |
| **Overall Performance** | Weighted combination of all metrics with historical comparison to track improvement |
| DATA SHARING WITH OTHER SERVICES | | |
| ----- | ----- | ----- |
| **Target Service** | **Data Shared** | **Purpose** |
| **Interview Service** | Voice/facial/body/technical/screen scores, weak communication areas, filler word patterns | Tailor interview questions to address roleplay gaps |
| **Assessment Service** | Topic performance, behavioral competencies, communication patterns, technical setup quality | Recommend targeted assessments for weak areas |
| **Course Service** | Skill gaps (communication, presentation, technical), low metric scores, setup quality issues | Recommend soft skills, communication, technical courses, setup guidance |
| **Dashboard Service** | Session count, certificates earned, performance scores (all metrics), credits remaining | Update Q-Score based on performance, show progress achievements, suggest improvements |
| ACCEPTANCE CRITERIA | | |
| :---: | ----- | :---: |
| **\#** | **Must Pass** | **Pass/Fail** |
| **1** | Avatar renders correctly. Voice synthesis works with lip-sync within 100ms. Fallback to text if voice fails. | \[ \] PASS \[ \] FAIL |
| **2** | User camera/microphone captured throughout session. All recordings stored in cloud. Download links work. | \[ \] PASS \[ \] FAIL |
| **3** | User can share specific window. Screen recorded alongside video/audio. User can stop sharing anytime. | \[ \] PASS \[ \] FAIL |
| **4** | AI analyzes voice including filler word COUNT (um, uh, like, you know). Counts displayed in feedback. | \[ \] PASS \[ \] FAIL |
| **5** | AI analyzes technical quality: Lighting (well-lit/acceptable/poor), Framing (centered/off-center), Background (professional/distracting), Audio quality (clear/noisy). | \[ \] PASS \[ \] FAIL |
| **6** | AI analyzes screen content: Code quality (syntax, structure, logic) for IDEs, Slide quality (design, clarity) for presentations, Demo completeness for apps. | \[ \] PASS \[ \] FAIL |
| **7** | All metrics calculated correctly (Voice, Facial, Body, Technical Quality, Screen Content). Overall weighted score accurate. Certificate generated for 70%+ on eligible scenarios. | \[ \] PASS \[ \] FAIL |

File diff suppressed because it is too large Load Diff