- 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
1176 lines
28 KiB
Markdown
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."
|