Files
docs/social_branding/plan-prd-implementation-audit.md
-Puter e6685203fe 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
2026-06-22 15:04:27 +05:30

1176 lines
28 KiB
Markdown

# Social Branding Service Audit
Date: 2026-03-23
## Purpose
This document compares:
1. the product BRD / PRD in [`docs/PRD.md`](./PRD.md)
2. the narrowed execution plan in [`docs/plan.md`](./plan.md)
3. the current implementation in `app/` and `tests/`
It is intended as a handoff and presentation document so another engineer or stakeholder can answer:
- what was planned
- what was actually built
- which decisions were taken to narrow scope
- which assumptions phase one was built on
- what is still missing versus the plan
- what is still missing versus the PRD
- what architecture should be used going forward
Auth is intentionally excluded from blocker status for this review. Future auth is assumed to be Clerk-issued JWT at the service boundary.
## Executive Summary
The current repo is best understood as a narrowed, LinkedIn-first individual-user MVP that is substantially aligned with the overnight plan, but not aligned with the full PRD.
The implementation does support the plan's core demo loop:
1. import a LinkedIn profile snapshot
2. compute a LinkedIn audit and Brand Score v1
3. infer or select a persona strategy
4. generate a 2-week content calendar with an 80/20 split
5. generate LinkedIn drafts
6. move drafts through approval, rejection, regeneration, and manual publish confirmation
7. expose dashboard and local event history
That flow is implemented and tested. `uv run pytest` passed with `4 passed, 1 warning` on 2026-03-23.
However, the repo is not PRD-complete. The PRD describes a broader multi-platform, more automated system with richer scoring, profile rewrites, live collection, scheduled posting, analytics, engagement automation, and enterprise workflows. Those are not implemented here.
The biggest architectural mismatch with the desired next version is this:
- the code already has some engine-like pure logic
- but the engine is not yet separated as an explicit domain package or service boundary
- orchestration, persistence, and business logic are still mixed inside one application service
- surfaces are currently HTTP-only in practice
- Redis and the worker exist as scaffolding, not as an active runtime path
## Canonical Scope Hierarchy
The repo currently has three levels of scope, and they should not be confused during presentation.
### 1. PRD scope
The PRD is the broad product target:
- individual plus enterprise
- LinkedIn, Instagram, X, YouTube
- automated connect -> collect -> analyze -> generate -> approve -> post -> track loop
- Brand Score feeding RQx
- richer content and analytics behavior
Relevant references:
- `docs/PRD.md:21-36`
- `docs/PRD.md:42-70`
- `docs/PRD.md:80-102`
- `docs/PRD.md:183-248`
- `docs/PRD.md:360-397`
### 2. Plan scope
The plan is the locked overnight MVP and is the real governing doc for what this repo was trying to ship immediately:
- individual only
- LinkedIn only
- manual import fallback instead of hard OAuth
- Brand Score v1 from available LinkedIn data
- content calendar, drafts, approval queue, manual publish confirmation
- dashboard and local events
- enterprise and multi-platform behavior deferred
Relevant references:
- `docs/plan.md:9-38`
- `docs/plan.md:78-128`
- `docs/plan.md:149-158`
### 3. Current implementation scope
The code matches the narrowed plan much more closely than it matches the PRD. It is therefore more accurate to describe the current service as:
"A request-driven, LinkedIn-first social branding MVP for individual users with manual ingestion, simplified scoring, deterministic content generation, approval workflow, dashboard summaries, and local event persistence."
That description is also how the README frames it:
- `README.md:3-23`
- `README.md:81-85`
## Current Architecture Assessment
## What exists today
The current architecture is:
- HTTP API surface in `app/api/v1/`
- one application service in `app/services/social_branding.py`
- several pure or mostly pure helper modules in:
- `app/services/brand_score.py`
- `app/services/persona_strategy.py`
- `app/services/content_calendar.py`
- persistence in SQLAlchemy models in `app/models.py`
- queue abstraction in `app/services/queue.py`
- a worker loop in `app/worker/main.py`
This is a valid MVP architecture, but it is not yet the target split you described.
## Desired target architecture
For the next version, the clean split should be:
### 1. Social branding engine
A pure, platform-agnostic decision engine that takes normalized inputs and produces outputs such as:
- audits
- scores
- persona strategy decisions
- calendar plans
- draft suggestions
- recommendation bundles
This layer should not know about:
- FastAPI
- SQLAlchemy sessions
- Clerk JWTs
- Redis
- Postgres
- HTTP request shapes
### 2. Social branding service layer
An orchestration layer that:
- receives authenticated user context
- loads and stores data
- calls the engine
- persists outputs
- emits events
- coordinates approval and posting workflows
- exposes use cases to surfaces
### 3. Surfaces
Adapters on top of the service layer, for example:
- HTTP API
- background worker consumers
- Redis/event consumers
- internal command handlers
- future admin or operator surfaces
### 4. External adapters
Per-platform collectors and posters:
- LinkedIn import adapter
- Instagram connector
- X connector
- YouTube connector
- GitHub connector (signals + content source)
- manual upload/import adapter
See also: `docs/external-adapters-plan.md` for the platform-compliance contract and phased implementation plan.
### 5. Infrastructure
- Postgres
- Redis
- storage
- auth verification
- observability
## How close the current code is to that shape
Partially aligned:
- `app/services/brand_score.py` already looks like engine logic.
- `app/services/persona_strategy.py` already looks like engine logic.
- `app/services/content_calendar.py` already looks like engine logic.
Not yet aligned:
- `app/services/social_branding.py` combines orchestration, persistence, workflow rules, and business decisions in one class.
- there is no explicit normalized engine contract
- there is no repository layer
- there are no platform adapter interfaces
- surfaces are API routes only in practical use
Conclusion:
The repo contains the beginnings of an engine, but the engine is still embedded inside the service implementation rather than clearly separated.
## What Was Implemented
## Data model and persistence
The main persistence model is present and broadly follows the plan:
- `social_accounts`
- `social_profile_snapshots`
- `brand_scores`
- `persona_strategies`
- `content_calendar_items`
- `content_drafts`
- `approval_queue`
- `posting_records`
- `analytics_snapshots`
- `engagement_drafts`
- `integration_events`
Reference:
- `app/models.py:58-235`
Observations:
- The model names mostly match the plan's domain model.
- `posting_records` and `integration_events` were added beyond the explicit plan list and are useful.
- `engagement_drafts` exists in schema only and is not actively used in the service flow.
- Everything is stored through `create_all()` on startup; there is no migration system yet.
## API surface
The HTTP routes listed in the README and plan are implemented:
- LinkedIn import
- persona select
- brand score recalculate
- content calendar generate/list
- drafts generate
- approval approve/reject/regenerate
- publish confirm
- dashboard
- events
- demo seed
- health
References:
- `README.md:25-39`
- `app/api/v1/__init__.py`
- `app/api/v1/accounts.py`
- `app/api/v1/brand_score.py`
- `app/api/v1/content.py`
- `app/api/v1/dashboard.py`
- `app/api/v1/events.py`
- `app/api/v1/demo.py`
- `app/api/v1/health.py`
- `app/api/v1/persona.py`
## LinkedIn ingest and audit
Implemented:
- manual LinkedIn import payload
- account upsert
- profile snapshot persistence
- section-level audit scoring
- recommendation list persistence
References:
- `app/services/social_branding.py:190-239`
- `app/services/brand_score.py:37-88`
What it actually does:
- scores headline, about, experience, skills, recommendations, featured, and activity
- persists overall score and recommendations
- uses simple heuristic thresholds, not benchmarked analysis
## Brand Score v1
Implemented:
- Brand Score computation on import
- manual recalculation endpoint
- score history persistence
- event emission when score changes materially or when forced
References:
- `app/services/social_branding.py:134-188`
- `app/services/social_branding.py:241-274`
- `app/services/brand_score.py:91-142`
What it actually does:
- computes five components:
- profile completeness
- content consistency
- engagement quality
- visibility
- audience growth
- uses LinkedIn metrics only
- stores local integration events in the service database
## Persona strategy
Implemented:
- six persona enums
- heuristic persona inference from pathway context
- manual persona override
- cadence, tone, target role, and source context persistence
References:
- `app/models.py:35-41`
- `app/services/persona_strategy.py:8-127`
- `app/services/social_branding.py:67-96`
What it actually does:
- infers persona from role and goals
- always assigns LinkedIn as the active platform
- stores one active strategy at a time per user
## Content calendar and drafts
Implemented:
- 2-week calendar generation
- 80/20 toolkit versus dynamic split
- deterministic topic sequencing
- LinkedIn draft generation
References:
- `app/services/social_branding.py:276-322`
- `app/services/content_calendar.py:26-84`
- `app/services/social_branding.py:360-459`
- `app/services/content_calendar.py:97-144`
What it actually does:
- uses persona cadence to create slots over 14 days
- marks some slots as dynamic using deterministic spacing
- chooses from a fixed toolkit topic list per persona
- generates simple template-based LinkedIn drafts
## Approval and publish flow
Implemented:
- queue item creation per draft
- approve
- reject
- regenerate
- posting state transitions
- manual publish confirmation
- local approval event emission
References:
- `app/services/social_branding.py:333-359`
- `app/services/social_branding.py:360-418`
- `app/services/social_branding.py:486-620`
What it actually does:
- every draft becomes an approval item and posting record
- approving immediately transitions the posting record to `ready_for_manual_publish`
- publish is confirmed manually by user-supplied external reference
## Dashboard and events
Implemented:
- latest brand score and recent trend
- queue summary
- posting state summary
- latest analytics snapshot view
- local event listing
References:
- `app/services/social_branding.py:622-705`
- `app/services/social_branding.py:707-722`
## Worker and queue
Implemented in scaffold form:
- queue backend abstraction
- database no-op backend
- Redis backend
- worker loop
References:
- `app/services/queue.py:1-83`
- `app/worker/main.py:14-36`
- `README.md:83-85`
Important reality:
- the current product flow is request-driven
- the worker does not execute domain jobs
- the Redis queue is infrastructure-ready, not feature-ready
## Test coverage
Implemented:
- health check
- happy path full MVP flow
- limited-data import path
- regenerate path state behavior
Reference:
- `tests/test_social_branding_flow.py:32-207`
Observed verification:
- command run: `uv run pytest`
- result: `4 passed, 1 warning`
## Phase-One Foundations: Decisions and Assumptions
The user asked specifically for the assumptions and decisions behind the current phase-one implementation. Those are below.
## Decision 1: Narrow to individual plus LinkedIn only
Why:
- the PRD is much broader than can be implemented quickly
- LinkedIn is the primary value surface in the PRD and plan
- multi-platform plus enterprise would have blocked delivery
Where it shows up:
- `docs/plan.md:11-30`
- `README.md:10-23`
- `app/services/persona_strategy.py:124`
- `app/services/social_branding.py:201-206`
- `app/services/social_branding.py:313`
Assumption:
- proving one strong individual LinkedIn flow is more valuable than partial support across four platforms
## Decision 2: Use manual import instead of OAuth-first collection
Why:
- the PRD explicitly leaves data collection method to engineering
- LinkedIn collection is the riskiest integration area
- the overnight plan avoids blocking on OAuth and unstable APIs
Where it shows up:
- `docs/PRD.md:36`
- `docs/PRD.md:240-248`
- `docs/plan.md:13`
- `docs/plan.md:35`
- `app/schemas/social_branding.py:47-52`
- `app/services/social_branding.py:190-239`
Assumption:
- GrowQR can seed or receive normalized LinkedIn data from a manual process, future adapter, or another service
## Decision 3: Treat Brand Score as a simplified v1
Why:
- the PRD's full seven-component score depends on data that does not exist in the narrowed MVP
- the plan explicitly says not to block on unavailable cross-platform metrics
Where it shows up:
- `docs/plan.md:36`
- `app/services/brand_score.py:18-24`
- `app/services/brand_score.py:91-142`
Assumption:
- a meaningful but incomplete score is acceptable for v1 if it is stable, stored, and trendable
## Decision 4: Use deterministic content generation instead of real AI orchestration
Why:
- the plan prioritizes demonstrating flow and content structure over model sophistication
- deterministic output is easy to test and explain
Where it shows up:
- `docs/plan.md:38`
- `app/services/content_calendar.py:26-84`
- `app/services/content_calendar.py:97-144`
Assumption:
- content templates and placeholders are enough for MVP validation
## Decision 5: Make publish manual-confirmed
Why:
- the plan explicitly allows manual publish confirmation
- live posting would introduce platform API risk and auth complexity
Where it shows up:
- `docs/plan.md:37`
- `app/services/social_branding.py:507-508`
- `app/services/social_branding.py:591-620`
Assumption:
- for v1, it is enough to generate approved content and let the user confirm it was posted manually
## Decision 6: Keep async infrastructure scaffolded but not operationally central
Why:
- Postgres and Redis are useful for future scale and service consistency
- the immediate flow can be run synchronously
Where it shows up:
- `README.md:75-85`
- `.env.example`
- `.env.docker`
- `app/services/queue.py:1-83`
- `app/worker/main.py:14-36`
Assumption:
- request-driven synchronous use cases are acceptable for phase one, with queue infrastructure reserved for later work
## Decision 7: Trust caller-provided `user_id`
Why:
- auth is intentionally out of scope
Where it shows up:
- almost every request schema accepts `user_id` directly, for example `app/schemas/social_branding.py:47-52`, `87-91`, `111-115`, `153-157`
Assumption:
- an upstream system or future JWT layer will replace body-supplied identity
## Implementation Status Versus Plan
The plan is mostly implemented, but some items are implemented in a thin MVP form rather than a durable production form.
## Phase 1: Foundations
Plan status: implemented
Evidence:
- social branding models exist in `app/models.py:58-235`
- persona enums exist in `app/models.py:35-41`
- brand score component model exists in `app/models.py:89-99`
- persona topic libraries exist in `app/services/persona_strategy.py:26-63`
Assessment:
- This phase is done for MVP purposes.
- The main gap is architectural: these foundations are not yet separated into engine/service/adapters.
## Phase 2: Profile ingest and audit
Plan status: implemented, simplified
Evidence:
- import endpoint exists
- manual payload fallback is the main supported path
- audit scoring and recommendations are persisted
- limited-data import test exists
Assessment:
- Done for MVP.
- Not equivalent to PRD-grade platform analysis.
## Phase 3: Brand Score and persona strategy
Plan status: implemented, simplified
Evidence:
- brand score is computed and stored
- persona inference and manual selection work
- score update events are persisted
Assessment:
- Done for MVP.
- The score model is intentionally reduced from the PRD.
- Events are local persistence records, not cross-service integration delivery.
## Phase 4: Content calendar and drafts
Plan status: implemented, partially shallow
Evidence:
- 2-week calendar exists
- 80/20 split exists
- LinkedIn draft generation exists
Assessment:
- Done for demo and workflow validation.
- Dynamic triggers are represented as preselected topic types, not event-driven runtime behavior.
- Drafts are deterministic templates, not model-generated or personalized beyond a few fields.
## Phase 5: Approval and publish flow
Plan status: implemented
Evidence:
- queue, approve, reject, regenerate, publish confirmation, and state transitions all exist
Assessment:
- Strongly implemented for the narrowed MVP.
- Still single-user only.
- No scheduling engine or platform posting adapter exists.
## Phase 6: Dashboard and hardening
Plan status: mostly implemented
Evidence:
- dashboard endpoint exists
- happy-path tests exist
- deferred scope is documented
Assessment:
- Done for MVP handoff and demo.
- Not hardening-complete for production.
- Missing migrations, background jobs, external integrations, auth, observability, and deeper test coverage.
## Implementation Status Versus PRD
This is the most important presentation distinction:
- plan alignment: mostly yes
- PRD alignment: no, not yet
## PRD items that are fully or mostly covered
### Individual personas exist
- six personas exist in the model
- persona selection and switching are present
Caveat:
- active platform mix is not implemented beyond LinkedIn
### LinkedIn-first audit and content flow exists
- LinkedIn import
- audit
- Brand Score v1
- calendar
- approval queue
- manual publish confirmation
### Brand Score history and dashboard exposure exist
- score history is persisted
- dashboard returns recent trend
## PRD items that are only partially covered
### Brand Score formula
PRD expectation:
- seven components
- RQx formula
- downstream event to Assessment and Pathways services
Current implementation:
- five components only
- no RQx mapping
- local event persistence only
References:
- `docs/PRD.md:82-102`
- `app/services/brand_score.py:18-24`
- `app/services/social_branding.py:174-188`
### Content model
PRD expectation:
- rich toolkit catalog and multiple dynamic triggers
- platform-aware formatting and platform mix rules
Current implementation:
- reduced toolkit topics
- three dynamic topic types
- LinkedIn-only output
References:
- `docs/PRD.md:141-181`
- `app/services/persona_strategy.py:26-63`
- `app/services/content_calendar.py:38-43`
### Analytics
PRD expectation:
- platform analytics per sync cycle
- richer performance tracking and trend lines
Current implementation:
- only snapshot summaries based on imported metrics
- no real recurring sync
- no per-content performance table
References:
- `docs/PRD.md:243-248`
- `docs/PRD.md:371-381`
- `app/models.py:198-211`
- `app/services/social_branding.py:656-696`
## PRD items that are not implemented
### Multi-platform runtime support
Not implemented:
- Instagram runtime collection/generation/posting
- X runtime collection/generation/posting
- YouTube analysis/brief generation/posting pipeline
Even though platform enums exist, runtime behavior does not.
References:
- `docs/PRD.md:21-24`
- `docs/PRD.md:198-235`
- `app/models.py:28-32`
### OAuth connect and recurring sync
Not implemented:
- platform OAuth flow
- scheduled sync jobs
- recurring collection cadence
- delta-based collector jobs
References:
- `docs/PRD.md:63-70`
- `docs/PRD.md:243-248`
- `app/worker/main.py:14-36`
### Profile rewrites and application to platform
Not implemented:
- rewrite generation for headline/about/experience
- approval flow for profile updates
- apply-to-platform action
References:
- `docs/PRD.md:190-193`
- no corresponding route or service use case exists
### Recruiter visibility and keyword gap analysis
Not implemented beyond basic visibility scoring inputs.
Missing:
- target-role benchmark
- keyword gap detection
- profile rewrite recommendations based on gaps
### Auto-posting and scheduling
Not implemented.
Current system only records manual publish confirmation.
References:
- `docs/PRD.md:68-70`
- `docs/PRD.md:179`
- `docs/PRD.md:369-381`
- `app/services/social_branding.py:591-620`
### Auto-approve mode
Not implemented.
The PRD explicitly calls for opt-in auto-approve.
References:
- `docs/PRD.md:179`
- `docs/PRD.md:376`
### Sensitive-topic filter and tone lock
Not implemented.
Missing:
- sensitive-topic classification before queueing
- tone locking after initial brand establishment
- policy-based regeneration or suppression
References:
- `docs/PRD.md:176-181`
### Engagement automation
Not implemented.
Notes:
- the table `engagement_drafts` exists
- no service flow populates it
- no routes expose it
References:
- `docs/PRD.md:56`
- `docs/PRD.md:168`
- `docs/PRD.md:194-195`
- `app/models.py:214-225`
### Enterprise social branding
Not implemented.
That entire scope is still absent.
References:
- `docs/PRD.md:250-397`
- `docs/plan.md:25`
## Key Product and Technical Assumptions Embedded in the Current Repo
These assumptions should be stated explicitly in any presentation so the current implementation is not oversold.
### Assumption: one service owns both business workflow and persistence
The code assumes one deployable service can hold:
- workflow logic
- persistence rules
- local event persistence
- API-facing use cases
This is acceptable for MVP, but it is why the engine is not yet truly reusable.
### Assumption: normalized external data will eventually arrive
The import request shape assumes someone else can provide:
- profile sections
- aggregate metrics
- pathway context
without this service solving collection first.
### Assumption: demo readiness was more important than platform completeness
This is visible in:
- deterministic content generation
- manual publish confirmation
- local event storage
- request-driven flow
### Assumption: Postgres and Redis are deployment options, not proof of async completeness
The repo can run on Postgres and Redis in Docker, but that should not be presented as meaning:
- scheduled jobs are implemented
- queue processing is meaningful
- Redis is part of the live product loop today
### Assumption: auth will be added upstream later
Today the service trusts request bodies for `user_id`.
For Clerk JWT integration, the service should move to:
- derive subject from JWT
- remove `user_id` from externally writable bodies where possible
- enforce per-user access at the service layer
## What Is Missing to Finish the Plan Properly
Strictly speaking, the plan's demo definition is met. But if "finish the plan properly" means "make the narrowed MVP robust and presentation-safe for handoff", the remaining work is:
### 1. Separate the engine from the service layer
Required:
- create an explicit engine package
- move pure decision logic out of application orchestration
- define normalized engine input and output contracts
Why:
- this is the biggest gap against the intended architecture
- it makes later multi-surface work cleaner
### 2. Add repository and adapter boundaries
Required:
- persistence repositories
- platform import adapters
- event publisher abstraction
- posting adapter abstraction
Why:
- right now platform, persistence, and workflow assumptions are tightly coupled
### 3. Replace startup `create_all()` with migrations
Required:
- Alembic or equivalent
Why:
- handoff and deployment reliability
- production schema evolution
### 4. Turn queue and worker into real use-case execution paths
Required:
- actual queued job types
- background handlers
- idempotency rules
- retry behavior
Why:
- the current worker is only scaffolded
### 5. Add stronger tests
Required:
- service-layer unit tests for engine outputs
- route-level error case tests
- Postgres integration tests
- Redis queue tests if worker becomes real
Why:
- current tests prove happy-path MVP behavior only
## What Is Missing to Reach the PRD
This is the longer roadmap beyond the narrowed MVP.
## Individual PRD completion
Required work:
- live or semi-live collection strategy per platform
- recurring sync engine
- full seven-component Brand Score
- RQx mapping and real cross-service event delivery
- profile rewrite generation and apply flow
- richer toolkit library
- real dynamic trigger ingestion
- topic safety filtering
- tone lock
- optional auto-approve mode
- scheduled posting adapters
- platform-specific formatting
- engagement queue generation
- richer analytics model and trend views
- platform activation recommendations per persona/archetype
## Enterprise PRD completion
Required work:
- enterprise account domain
- company brand voice settings
- governance rules and flags
- multi-role approvals
- enterprise content types
- enterprise analytics
- enterprise content calendar visibility and role actions
## Recommended Next Architecture and Work Packages
If the goal is to build toward the plan and finally the PRD while matching the desired split, the implementation sequence should be:
## Work Package 1: Explicit engine extraction
Create a package such as `app/engine/` or `app/domain/engine/` with:
- audit engine
- score engine
- persona engine
- calendar engine
- draft engine
Inputs should be normalized Python models, not SQLAlchemy rows.
## Work Package 2: Application service boundary
Refactor `SocialBrandingService` into use cases such as:
- import_profile
- select_persona
- recalculate_brand_score
- generate_calendar
- generate_drafts
- approve_content
- reject_content
- regenerate_draft
- confirm_publish
- get_dashboard
Each use case should orchestrate repositories and engine calls.
## Work Package 3: Adapter layer
Add adapter interfaces for:
- profile collectors
- posting executors
- event publishers
- analytics ingestors
Start with:
- manual import adapter
- LinkedIn placeholder adapter
## Work Package 4: Surface layer cleanup
Keep surfaces thin:
- HTTP API maps requests to use cases
- worker consumes jobs and invokes use cases
- Redis/event subscribers invoke the same use cases
## Work Package 5: Auth integration
When Clerk JWT is added:
- resolve user identity from token
- remove body-driven identity where possible
- add service-layer authorization guards
## Work Package 6: Platform expansion
After the architecture split is in place:
- add Instagram adapter
- add X adapter
- add YouTube adapter
Do not add those directly into the current `SocialBrandingService` shape, or the service will become harder to evolve.
## Final Readout
## What is done
The narrowed LinkedIn-first MVP is real and working:
- ingest
- audit
- Brand Score v1
- persona strategy
- 2-week calendar
- LinkedIn drafts
- approval queue
- manual publish confirmation
- dashboard
- local events
- demo seed
- tests passing
## What decisions were taken
The implementation intentionally chose:
- LinkedIn-only runtime
- manual import over OAuth-first
- simplified Brand Score
- deterministic templates
- manual publish confirmation
- request-driven flow
- local event persistence
- deferred auth
## What assumptions phase one was built on
Phase one assumes:
- upstream or manual data can be provided
- one-user flows are enough for validation
- live posting is not required
- local persistence is enough to prove the workflow
- Redis/Postgres readiness is useful even without full async execution
- the engine can be extracted later from the current helper modules and service logic
## What is left versus the plan
Very little is left for the narrowed MVP feature set itself. The main unfinished work is structural and production-grade:
- engine extraction
- repository/adaptor boundaries
- migrations
- real worker jobs
- broader tests
## What is left versus the PRD
A large amount remains:
- multi-platform support
- real collection and sync
- richer scoring and RQx integration
- profile rewrites
- scheduled posting
- engagement automation
- richer analytics
- safety and policy logic
- enterprise workflows
## Bottom line
This repo should be presented as:
"Plan-complete for a narrowed LinkedIn-first MVP, but not PRD-complete. The next major step is not adding random features inside the current service. It is separating the engine from the service and surfaces so the PRD can be implemented cleanly."