Sales workflow · Case study

From scattered sales context to a proposal a client can safely open.

Agencies build proposals from calls, emails, pricing sheets and specialist reviews. GetPosals turns that scattered work into one lead-to-signature flow, without pretending that an AI draft or a generated link is trustworthy before the system proves it.

Product
Proposal Buddy at CodeBuddy
Portfolio name
GetPosals
Role
Design and engineering owner
Timeline
Feb to Aug 2026
Users
Agency sales and review teams
Scope
Product design, build direction, QA, deployment
GetPosals dashboard with lead and proposal summaries, recent activity, and a browser-only workspace notice
  1. 01 / Trust stateThe persistent notice says this workspace is stored in the current browser and is not shared with teammates.
  2. 02 / Working setLeads, proposals, pipeline value and recent activity stay in the first scan.
Fig. 01The home screen puts leads, active proposals, pipeline value and recent work in one scan. The notice above the workspace states that this release stores team data in the current browser.

Real local product capture · fictional workspace data · captured Aug 2026

01

The proposal problem

A proposal starts before anyone opens an editor. Requirements sit in calls and email. Pricing lives in a separate sheet. Finance, technical and compliance reviewers add decisions in other tools. When those inputs stay disconnected, the sales owner spends more time rebuilding context than shaping the deal.

The product brief asked for one path from lead capture to signed contract. The harder design problem was deciding where the system could accelerate judgement, and where it had to slow down and make responsibility visible.

01 / Context

Inputs arrive in fragments

Discovery notes, files, links and lead history need to become one usable brief before drafting begins.

02 / Ownership

Review is shared, accountability is not

Specialists can contribute, but one execution owner still needs to move the proposal forward.

03 / Trust

A client link has to be real

A convincing success state is harmful when the proposal was not persisted or the client cannot open it.

The product had to compress the work without compressing the judgement around it.

PROPOSAL, DRAFTED WITH AIAI suggests scope + pricingfrom past winning proposalsSend →PIPELINE · APPROVALSDraftReviewSentWonWHAT ACTUALLY CONVERTS
Fig. 02The working model joins proposal drafting, pipeline control and learning loops. It is a schematic, not a product capture.
02

How I framed it

I owned product design and engineering at CodeBuddy. I later renamed the work GetPosals for this portfolio. Where AI helped write code, I designed the behaviour, set the constraints, directed the build and verified the result.

  1. Start from a lead, never a blank contextEvery proposal stays attached to the company, contact, documents, value and ownership that produced it.
  2. Separate assisted and manual creationProGenie can structure discovery, while a blank route remains available for confidential or highly custom work.
  3. Treat generation as a draft, not approvalPricing, scope, internal review and client delivery remain explicit steps after content is produced.
  4. Make trust states literalThe interface must distinguish Gemini output, guided fallback, local storage and a genuinely persisted public link.
Evidence rule: this case study reports what the product, source documents and verification logs show. It does not claim conversion lift, revenue impact or time saved.
03

The product decisions

I did not organise the work as a parade of design phases. The useful story is in the choices that changed how the system behaves.

Decision 01

Make the lead the source of proposal context

A proposal cannot exist without a lead. Starting from lead detail carries company, contact, value and attached documents into either the AI-assisted route or a blank draft.

The tradeoff is more structure at the start. I kept it because it removes the more expensive work of reconnecting a proposal to its source later.

GetPosals lead management table with company, source, owner, value, stage and proposal activity
Fig. 03Lead management keeps source, owner, value and proposal activity together before the drafting path begins.
Decision 02

Keep AI assistance separate from blank creation

ProGenie collects discovery context through chat, files, pasted text, links and custom instructions. A separate blank path opens the editor without an AI conversation.

Combining both into one smart editor looked simpler, but it made confidential work and direct drafting feel like edge cases. Two explicit starts make the system's behaviour easier to predict.

GetPosals ProGenie assistant with files and links at left, discovery conversation in the center, and a guided-mode provenance label
  1. 01 / GroundingFiles, pasted notes and links keep source context visible beside the conversation.
  2. 02 / ProvenanceThe response state distinguishes Gemini output from the guided fallback.
Fig. 04ProGenie keeps source material in the side panel and the discovery conversation in the main workspace. Its provenance label tells the user whether the response came from Gemini or the guided fallback.
Decision 03

Use one document model with two ways to navigate it

The editor keeps the same proposal sections and controls while letting the author switch between visual thumbnails and a compact list.

Thumbnails help with page shape. The list gives long proposals a faster scan. The content does not move to a different editor, so the user can switch views without losing context.

GetPosals proposal editor with page thumbnail navigation
Fig. 05Thumbnail view makes page shape visible.
GetPosals proposal editor with compact section list navigation
Fig. 06List view makes a long document faster to scan.
Decision 04

Make the collection a table by default

Proposal work is comparative. Status, owner, value, score and dates need to line up so a sales owner can scan across records without opening each one.

A card collection would give each proposal more personality, but it would hide the differences that matter in pipeline review. The shipped collection is table-only; the list and thumbnail toggle belongs to the editor.

GetPosals proposals table with filters, row selection, status, owner, value, score, dates and actions
Fig. 07The proposal collection defaults to a compact table with filters, selection, direct row actions and pagination.
04

The client handoff

The proposal is not finished when the editor looks complete. The decisive moment is the handoff: create a persisted share record, explain what the system did, and give the client a focused view that does not expose internal analytics or recipient history.

GetPosals send-to-client flow with recipient and delivery controls
Fig. 08The compose step collects the recipient and delivery options before any success state appears.
GetPosals proposal sharing flow with a persisted client link and copy action
Fig. 09The review step shows exactly what the client will receive and keeps link creation separate from email delivery.
Public GetPosals client proposal with branded summary, scope, delivery plan, investment and comments
Fig. 10The public proposal keeps the commercial story, scope, delivery plan and investment in one client-facing surface. This local capture uses fictional proposal data; production share isolation was verified separately.
GetPosals proposal statistics tab with share activity and client engagement information
Fig. 11The statistics design puts view activity and engagement in the proposal detail. Values shown here are product demo data, not customer outcomes.
05

The production gap

On 10 August 2026 I audited the live site in a browser. The frontend looked finished, and the backend health endpoint worked on its own Worker. But the two were not connected on the production domain. The product's most important actions were failing at the seam.

01 / What broke

Client links opened dead pages

Send appeared successful, while PDF export returned 405 and ProGenie silently fell back to scripted content.

02 / How I found it

I reproduced each path live

I compared browser network traffic, console output, production responses and the source that handled fallback behaviour.

03 / Root cause

The domain only served static assets

API requests hit the SPA fallback. GET returned HTML; POST and PUT returned 405. The healthy API Worker was never reached.

04 / What shipped

A route and a stricter trust policy

I restored the API source, bound the Worker route, removed fake offline links and labelled AI fallback honestly.

Source: live production audit, gap analysis and resolution record · 10 Aug 2026

200 HTML / 405
Before · wrong production handler

Same-origin API reads returned the app shell. Writes stopped at the static asset handler.

JSON fully-bound
After · API Worker route

The production domain reached D1, R2 and Gemini through the existing server-side Worker.

Source: same-origin health checks recorded before and after the Aug 2026 deployment

The fix changed the product's honesty

Routing fixed the connection, but it did not fix the product's promises. I also changed the rules around failure. A share link is shown only after persistence. Send confirms link creation, not email delivery. Deterministic fallback is labelled as a guided flow, never Gemini output. Browser-local workspace data is disclosed globally.

06

What changed

I do not have adoption, revenue or proposal-conversion data for this release. The honest outcome is a working product with a verified client-delivery path, plus clearer limits around what remains local to one browser.

22 / 22
Quota-free unit tests passed

Routing, fallback, proposal mapping and helper behaviour.

3 / 3
Production smoke tests passed

Gemini, PDF and internal comment paths after deployment.

2 / 2
Responsive checks passed

Desktop at 1440 by 1000 and mobile at 390 by 844.

Source: testing-and-validation.md and gap-resolution-plan-2026-08-10.md · recorded 10 Aug 2026

Accepted limitation: workspace entities still live in the current browser. Secure team sync needs authentication, workspace membership, role checks, conflict handling and a data migration plan. I chose disclosure over exposing an unauthenticated shared write API.
07

What changed in my thinking

I used to treat a polished success state as the end of a flow. This product made the backend receipt part of the interface. If the system cannot prove that a link exists, the design should not congratulate the user.

Owning design and engineering also made tradeoffs harder to hide. A card layout can look calmer while making comparison worse. A single AI route can look simpler while making manual work feel broken. The implementation forced each choice to survive real data, failure and deployment.