← Build log

When UI Constraints Drive Architecture: How 'No Scrolling' Shaped Our History Feature

A Technical Product Manager’s Guide to Letting UX Principles Drive Technical Decisions

By: Jeremy (20 years building products, now coding them myself)


After two decades as a technical product manager, I thought I understood the relationship between UX constraints and architecture decisions. Then I started building VoiceCatcher myself, and learned that seemingly tiny UI principles can completely reshape your entire technical approach.

Here’s the story of how a simple “no scrolling in the main UI” constraint forced us to architect a completely different solution—and why that constraint was worth every line of code it demanded.

The Setup: A Simple History Feature Request

The requirement seemed straightforward: “Users need to view their previous voice transcription sessions.”

In most apps, this would be a simple embedded list with scrolling. As a TPM, I’d seen this pattern a thousand times:

  • Add a scrollable container
  • Render the list items
  • Call it done

But VoiceCatcher had one non-negotiable design principle: The main UI should never require scrolling.

Why “No Scrolling” Matters: The Business Logic

This wasn’t arbitrary design stubbornness. The constraint served three critical business goals:

1. Cognitive Load Reduction

Voice capture tools need to be invisible during use. Any UI that requires exploration, scrolling, or hunting interrupts the user’s primary workflow. When someone hits our hotkey, they want immediate access to their most important controls.

2. Professional Tool Standards

Apps like Alfred, Raycast, and Spotlight have trained users to expect compact, single-screen interfaces for productivity tools. Scrolling signals “complex application” rather than “instant utility.”

3. Mathematical Precision

Our main UI is exactly 350×700 pixels in compact mode, 900×700 in expanded mode. Every pixel has a purpose. Scrolling would mean we failed to prioritize properly.

The Architectural Cascade: When Constraints Have Consequences

Here’s where it gets interesting for TPMs: One UX constraint triggered a complete architectural rethinking.

Attempt 1: Embedded History Tab

The obvious solution: Add a third expandable section after “Essential” and “Advanced” settings.

The problem: With our existing 700px height limit, adding a meaningful history list (showing 5-6 sessions) would require 400-500px. This pushed our total height past our no-scrolling constraint.

Lesson learned: Always calculate your UI math before committing to technical approaches.

Attempt 2: Compressed History Preview

The compromise: Show just 2-3 recent sessions in a tiny preview area.

The problem: User research (okay, it was just me testing it) revealed that 2-3 sessions provide almost no value. Users wanted to browse 10-20 sessions to find specific conversations from “last Tuesday” or “that client call.”

Lesson learned: When UX constraints force you to compromise core functionality, you’re solving the wrong problem.

Attempt 3: Popup Window Architecture

The solution: Completely separate the history feature into a dedicated popup window.

This wasn’t just a UI decision—it was an architectural pivot that required:

  • New IPC communication channels
  • Shared CSS architecture between windows
  • Window management complexity
  • Cross-window state synchronization

The Technical Implementation: TPM Communication Made Real

As TPMs, we often describe technical work without fully understanding the implementation complexity. Here’s what “just make it a popup” actually meant:

1. IPC Handler Development

// What the TPM says: "Open history in a new window"
// What the engineer builds:
async ['open-history-window']() {
  if (historyWindow && !historyWindow.isDestroyed()) {
    historyWindow.focus();
    return;
  }

  historyWindow = new BrowserWindow({
    width: 800,
    height: 700,
    frame: false,
    titleBarStyle: 'hidden',
    // ... 15 more configuration options
  });
}

2. Shared Design System

The popup needed to feel like part of the main app, requiring:

  • Shared CSS variables and components
  • Consistent neumorphic design patterns
  • Proper build process to copy assets
  • Theme synchronization between windows

3. Window Lifecycle Management

  • Prevent multiple history windows
  • Handle window focus and restoration
  • Manage memory cleanup on close
  • Coordinate with main window state

The Prompts That Made This Possible

For TPMs who want to implement similar solutions, here are the key prompts that drove our architectural decisions:

Constraint Evaluation Prompt

Analyze this UX constraint: [specific constraint]
1. What business value does this constraint provide?
2. What technical complexity does it add?
3. What alternative solutions preserve the constraint?
4. What is the cost/benefit ratio of maintaining this constraint?

Architecture Decision Prompt

Given this constraint: [no scrolling in main UI]
And this requirement: [show 10-20 history items]
Generate 3 technical approaches that satisfy both:
1. Include technical complexity assessment
2. Include user experience trade-offs
3. Include development time estimates

Implementation Planning Prompt

For a popup window solution:
1. List all IPC communication requirements
2. Identify shared resources (CSS, assets, state)
3. Plan window lifecycle management
4. Design error handling for window failures

The Results: When Constraints Create Better Products

Six months later, the popup history window is one of VoiceCatcher’s most praised features. Here’s why the constraint was worth it:

User Experience Wins

  • Main UI remains instantly accessible
  • History browsing doesn’t interrupt primary workflow
  • Dedicated space allows for rich history features (search, filtering, etc.)
  • Users can keep history open while using main app

Technical Architecture Wins

  • Modular window architecture enables future features
  • Shared design system scales to new windows
  • IPC patterns established for cross-window communication
  • Memory isolation prevents history data from slowing main UI

Business Value Wins

  • Professional tool aesthetic maintained
  • User workflow remains uninterrupted
  • Foundation for advanced features (AI processing, bulk operations)
  • Competitive differentiation from “just another list”

The TPM Framework: Making Constraint-Driven Decisions

Here’s the decision framework I now use for constraint-driven architecture:

1. Constraint Validation

  • Does this constraint serve real user value?
  • Does it differentiate our product meaningfully?
  • Is it worth the technical complexity it creates?

2. Solution Space Exploration

  • What are 3 completely different approaches?
  • Which approach best preserves the constraint while meeting requirements?
  • What technical debt does each approach create?

3. Implementation Reality Check

  • What’s the actual development complexity (days/weeks)?
  • What new architectural patterns does this introduce?
  • How does this scale to future requirements?

4. Success Metrics Definition

  • How will we measure if the constraint was worth it?
  • What user behavior changes do we expect?
  • What technical metrics will we track?

For TPMs: You Can Build This Yourself

The most important lesson from this experience: As a TPM, you can absolutely implement these solutions yourself.

The tools that made this possible:

  • Cursor + Claude: For real-time implementation guidance
  • Electron: For desktop app architecture
  • TypeScript: For architectural safety
  • Clear constraint definition: For focused decision-making

The skills you need aren’t mysterious engineering magic—they’re systematic thinking patterns you already use as a TPM, applied to code.

Practical Next Steps

If you’re a TPM wanting to try constraint-driven development:

Start Small

Pick one strong UX constraint in your current product. Trace through how it affects technical decisions.

Use This Prompt Template

I need to implement [feature] while maintaining [constraint].
Show me 3 architectural approaches:
1. Embedded solution with constraint modifications
2. Separate interface preserving constraint
3. Hybrid approach with partial constraint relaxation

For each approach, include:
- Development complexity (1-10 scale)
- User experience trade-offs
- Long-term maintenance considerations

Measure Everything

Track both user behavior and technical metrics. Constraints should improve both.

The Bottom Line

Great products come from great constraints, not from avoiding them.

When you encounter a UX constraint that seems to make technical implementation harder, that’s often a signal you’re onto something valuable. The question isn’t “how do we work around this constraint?” but “how do we build an architecture that makes this constraint feel natural?”

In VoiceCatcher’s case, “no scrolling” wasn’t a limitation—it was a design principle that forced us to build a better, more modular architecture. And as TPMs, learning to implement these solutions ourselves doesn’t just make us better at our jobs—it makes us better at building products that actually serve users.

The constraint drove the architecture. The architecture served the users. The users validated the constraint.

That’s the cycle that builds great products.


Jeremy is a technical product manager turned solo developer, building VoiceCatcher as a local-first voice transcription tool. Follow the journey at [project repo] or connect on [social links].

Next in this series: “The Three-Attempt Rule: Technical Problem-Solving in Product Development” - How we solved the history window scrolling issue that failed twice before finding the right solution.