A prototype built around an IT consultancy's problem: research a prospect, work out who's worth talking to, and draft outreach that's grounded in what the company actually does and the work the consultancy has already done.
C#
ASP.NET Core
PostgreSQL
Applied AI
01 / The problem
Outreach only sounds personal if the system actually knows something.
This started as a side project after some open ended conversations with an IT consultancy. The question I kept coming back to was whether research on a prospect could actually turn into outreach that sounds like a person wrote it. To get there it had to find the right contacts, understand what the company is actually dealing with, tie that to work the consultancy had already done, and still let the sender decide the tone. Delivery turned out to be the harder half. LinkedIn doesn't allow unauthorized automation, so writing something worth sending and actually sending it across channels are two very different problems.
End-to-endresearch-to-outreach prototype built independently
02 / Architecture
Clear boundaries meant research, rules, generation, and delivery could each be swapped without disturbing the others.
A Vue frontend calls thin ASP.NET Core endpoints, which delegate to single-purpose application use cases and domain entities. Repository and service interfaces isolate PostgreSQL, CRM intake, web research, AI providers, and channel delivery. That let me build the whole path from research to a scheduled workflow, while the uncertain part, actually sending email and LinkedIn messages, stayed at the edge where it's easy to replace.
03 / Engineering
The decisions behind the system.
01
Multi-source company and contact enrichment
Give it a company name and a domain and it builds a picture of that company. The rule underneath is that no single source and no single model answer gets to be the truth on its own.
Implementation details
First-party website analysis and external signal discovery run concurrently before their evidence is merged
Synthesis prioritizes company-owned material for stable facts and external sources for recent hooks
Freshness, source quality, deduplication, and traceability aren't handled yet and would be needed before real use
Enrichment / Two evidence tracks01 / 02
01Collect — parallel evidence tracks reduce dependence on a single source.02Synthesize — ranked evidence becomes reusable company and contact context.
02
Context-aware outreach generation
Writing a draft isn't one prompt. Most of the work is deciding what the model should know before it writes anything, and the sender still owns how it sounds.
Implementation details
The context builder combines prospect intelligence, the active contact, sender identity, company positioning, previous cases, and a channel prompt
Separate strategies support collected-data and web-search paths for email and LinkedIn content
Drafts remain editable and support conversational revision, while factual and stylistic review stays human-owned
Generation / Context before content01 / 02
01Context — research, identity, positioning, cases, and prompt settings become explicit inputs.02Refine — the generated draft stays editable and can be revised through conversation.
03
Stateful multi-channel workflow engine
A sequence you wrote once becomes a real schedule for one specific prospect. Before it's allowed to start, the system checks that everything it's going to need actually exists.
Implementation details
Ordered steps support email, LinkedIn messages, connection requests, waits, and lightweight interactions
Activation validates enrichment and generation requirements before converting local offsets into scheduled timestamps
A background worker and executor are implemented, but channel actions are still mock adapters, so nothing is actually sent yet
Workflow / Validate before execution01 / 02
01Lifecycle — incomplete sequences are stopped before they can be activated.02Boundary — orchestration is implemented while external delivery remains replaceable.
04
Clean Architecture around volatile integrations
I rebuilt the backend around clear layers so no external provider ends up owning the logic. The integrations plug in at the edges and can be replaced without touching the core.
01Draft — review generated outreach beside the conversational refinement workspace.02Voice — maintain channel-specific instructions for email and LinkedIn outreach.03Company context — store positioning and previous cases as reusable generation inputs.04Prospects — manage manually created and CRM-sourced targets from one workspace.
05 / Evaluation
Tested and reviewed with the consultancy, but never used in production.
I built it alongside an ongoing dialogue with the consultancy. We walked through the workflow together at regular points, and their feedback on how they actually find and approach prospects decided what I built next, from how contacts get selected to how much control the sender keeps over tone. Unit tests over the domain rules and main use cases back that up, so the parts that exist behave the way we agreed they should.
Around the same time, they adopted a commercial tool that already had approved LinkedIn access, the one integration I couldn't build on my own terms. That settled the build or buy question for them, and it's why this stayed a prototype.
06 / Outcome
A working prototype, built together with the people who would use it.
It connects the whole path: pull in a prospect, research the company and the people in it, bring in previous client work, generate a draft you can edit and revise by chatting with it, then schedule the sequence. Building it next to the people who would actually use it meant every step had to hold up against how they really sell, not how I imagined they did.
Delivered
The whole path end to end: prospect intake, research, contact enrichment, drafting, revising by conversation, settings, and workflow scheduling.
Validated
Regular conversations with the consultancy kept it tied to how they actually work, and tests plus interface walkthroughs confirmed the parts that exist behave the way they should.
Next
Sending anything for real would need approved channel integrations, better traceability back to sources, wider integration tests, and actual users.