Skip to content
··閱讀時間4分鐘

Blank Screens Kill Trust。我有31個。

我喺我嘅SaaS入面搵到31個blank screens——全部因為我忘記咗multi-tenancy唔止係data access,佢仲係URL context。以下係Claude Code點幫我一晚fix晒嘅故事。

11月1日,朝早8:47。我收到封email。

「Hey Chandler——我㩒咗『View』然後得到blank page。我係咪整冇咗我所有interview data?」

我個胃沉咗落去。Blank pages唔係bugs。佢哋係trust killers。

我打開dev console。Check咗個route。Agency user,睇緊client「Acme Corp」,㩒咗個button,然後...URL由/clients/acme-corp/agents/agent-name/results/123變咗做/agent-name/results/123

Lost咗client context。React Router搵唔到個route。Blank screen。

「Okay,嗰個係一個bug,」我諗。「我fix咗佢然後move on。」

我setup Claude Code分析codebase搵similar patterns,然後同家人過咗個Saturday。Lunch。做嘢。小朋友。正常嘅嘢。

到下晝遲啲,我check返。Claude Code搵到個pattern——而且唔係好睇。

到7:42 PM,我fix咗14個bugs。到7:48 PM,搵多8個。到7:56 PM,total去到31個

全部同一個root cause。全部同一個fix。全部因為我build multi-tenancy嘅時候忘記咗一件事:navigation唔止係data,佢係context。

---

到底有幾差?

等我老實講呢31個bugs actually意味住咩:

For users:

- Agency users撞到blank screens(睇起嚟broken,唔止係buggy)

- Mid-session lost workflow progress

- 「呢個platform夠唔夠stable for我哋嘅clients?」

- 每個blank screen = closer to取消trial

For我:

- 每日5+個bug reports(全部navigation-related)

- 每個individually debug 2-3個鐘

- Ship唔到新features(太忙firefighting)

- 真正嘅恐懼:「如果我break咗其他嘢而我唔知呢?」

Existential question: 如果我連navigation都搞唔掂,點解有人應該trust STRAŦUM handle佢哋clients嘅marketing strategy?

Blank screens kill trust比任何嘢都快。

---

一切嘅開端

等我show你exactly發生咗咩。

User flow(應該work嘅):

1. 去/clients/acme-corp/agents/analysis

2. 㩒「Start Session」

3. Complete analysis

4. 㩒「View Results」

5. 喺/clients/acme-corp/agents/analysis/results/123見到results

Actually發生咗咩:

1. ✅ /clients/acme-corp/agents/analysis(good)

2. ✅ Start session(working)

3. ✅ Complete analysis(data saved)

4. ❌ **㩒「View Results」→ BLANK PAGE**

5. ❌ URL變咗做/analysis/results/123(lost client context)

React Router搵/analysis/results/123嘅route。For agency users唔存在。Render nothing。

User見到:Blank white screen。冇error message。冇loading spinner。只係...nothing。

---

我(其實Claude Code)開始Dig嘅時候搵到咩

以下係broken code嘅樣:

```typescript
// AgentPage.tsx (SANITIZED - the broken pattern)
import { useParams, useNavigate } from 'react-router-dom';

export function AgentPage() {
  const { clientSlug } = useParams<{ clientSlug: string }>();
  const navigate = useNavigate();

  const handleViewResults = (sessionId: string) => {
    // Problem: Hardcoded route, no client context
    navigate(`/agent-name/results/${sessionId}`);
  };

  return (
    // ... component
  );
}
```

見到個問題嗎?

我由URL extract咗clientSlug。我用佢嚟fetch data。但當我navigate嘅時候,我完全忘記咗佢。

Agency routes長咁:/clients/acme-corp/agents/agent-name

SME routes長咁:/agent-name

我hardcode咗SME pattern。Agency users = broken。

---

發現:我有31個呢啲

2:15 PM。我fix咗第一個bug。Committed。感覺唔錯。

3:42 PM。喺另一個agent搵到另一個。同一個pattern。Fix咗。

4:18 PM。另一個agent。一樣嘅嘢。

5:30 PM。我停低咗盯住個screen成10分鐘。

每個agent page都有同一個bug。 每個navigate嘅nested component。每個有「Go to...」button嘅shared UI element。

我可以逐個fix然後花2日。或者我可以搵到pattern然後systematically fix晒。

我揀咗systematic。

---

Fix:Context-Aware Navigation

唔係喺每個component用useParams(),我叫Claude Code create一個Context provider:

```typescript
// contexts/ClientContext.tsx
import { createContext, useContext } from 'react';
import { useParams } from 'react-router-dom';

interface ClientContextValue {
  clientSlug: string | null;
}

const ClientContext = createContext<ClientContextValue | null>(null);

export function ClientContextProvider({ children }: { children: React.ReactNode }) {
  // Extract clientSlug ONCE at the layout level
  const { clientSlug } = useParams<{ clientSlug: string }>();

  return (
    <ClientContext.Provider value={{ clientSlug: clientSlug || null }}>
      {children}
    </ClientContext.Provider>
  );
}

export function useClientContext() {
  const context = useContext(ClientContext);
  if (!context) {
    throw new Error('useClientContext must be used within ClientContextProvider');
  }
  return context;
}
```

然後我wrap咗agency routes:

```typescript
// App.tsx
<Route path="/clients/:clientSlug/*" element={
  <ClientContextProvider>
    <ClientLayout />
  </ClientContextProvider>
}>
  <Route path="agents/analysis" element={<AnalysisAgent />} />
  <Route path="agents/strategy" element={<StrategyAgent />} />
  {/* ... all client-scoped routes */}
</Route>
```

而家入面每個component都可以透過context access clientSlug,唔係params。

Routing helper(因為打同一個if/else 20次會悶):

```typescript
// hooks/useContextRoute.ts
import { useClientContext } from '@/contexts/ClientContext';

export function useContextRoute() {
  const { clientSlug } = useClientContext();

  const buildRoute = (route: string) => {
    if (clientSlug) {
      // Agency route: /clients/acme-corp/agents/...
      const cleanRoute = route.startsWith('/') ? route.slice(1) : route;
      return `/clients/${clientSlug}/${cleanRoute}`;
    }
    // SME route: /agent-name/...
    return route;
  };

  return { buildRoute, clientSlug };
}
```

用法(clean好多):

```typescript
// AgentPage.tsx (SANITIZED - the fixed pattern)
import { useClientContext } from '@/contexts/ClientContext';
import { useNavigate } from 'react-router-dom';
import { useContextRoute } from '@/hooks/useContextRoute';

export function AgentPage() {
  const { clientSlug } = useClientContext();
  const { buildRoute } = useContextRoute();
  const navigate = useNavigate();

  const handleViewResults = (sessionId: string) => {
    // This works for BOTH SME and Agency users
    navigate(buildRoute(`agents/analysis/results/${sessionId}`));
  };

  return (
    // ... component
  );
}
```

一個helper function。Context-aware。For兩種user types都work。

---

Systematic Fix:一日,31個Files

有咗pattern之後,佢變成mechanical嘅。

2025年11月1日——Sprint

下晝(2 PM - 7 PM)——Finding同categorizing:

- 發現個pattern across所有agent pages

- Build咗Context provider同routing helper

- 喺第一個agent test咗approach

晚上(7:00 PM - 8:00 PM)——Systematic fix:

7:42 PM——第一波(14個bugs):

```
fix(multi-tenant): fix 14 navigation bugs and refactor all agents to useClientContext()

Frontend Changes (8 files):
- Refactored 6 agents to use useClientContext() hook
- Fixed 14 navigation bugs that lost client context across multiple agents

Backend Changes (5 files):
- Added client_id parameter to all save operations
- Updated base classes to extract client_id properly

Files changed: 14
Insertions: +732
Deletions: -164
```

7:48 PM——第二波(多8個bugs):

```
fix(multi-tenant): fix 8 navigation bugs in strategy page

- Fixed 8 navigation buttons that lost client context
- Total bugs fixed: 22 (14 + 8)

Files changed: 1
Insertions: +71
Deletions: -23
```

7:56 PM——最後一波(多9個bugs):

```
fix(multi-tenant): fix 9 navigation bugs in interview and tool pages

- Fixed remaining navigation issues in nested components
- Total bugs fixed: 31 bugs across entire application

Files changed: 2
Insertions: +46
Deletions: -10
```

我跑遍每個agent flow。SME user。Agency user。㩒每個button。冇blank pages。

Total damage: 17個files changed,849 insertions,197 deletions。

投入時間: 大約6個鐘non continuous work有Claude Code(2 PM discovery → 8 PM final commit)。

節省時間: 可能30+個鐘嘅individual bug fixes同user support。

---

我(Hard Way)學到嘅嘢

1. Multi-tenant navigation比data isolation更難

你可以用org_id filter data。嗰個係easy part。

但navigation?你有同一個feature嘅兩個valid URL structures

```
SME:    /agent-name/session/123
Agency: /clients/acme-corp/agents/agent-name/session/123
```

每個navigate()call都需要知用邊個pattern。搞錯一次,users就見到blank pages。

2. useParams()會騙你

```typescript
const { clientSlug } = useParams();
```

呢個work...直到route change。然後clientSlug變成undefined,你嘅下一個navigation就break。

React Context唔會騙你。佢always available,always consistent。

3. Claim victory之前count每個bug

我以為有14個bugs。然後搵多8個。然後多9個。

Lesson: Grep你成個codebase,唔只係你以為有bugs嘅files。

4. 當你搵到同一個bug兩次,停落嚟create一個pattern

Individual fixing: 31個bugs = 可能一個禮拜

Systematic fixing: 搵pattern → Create helper → Fix所有instances = 6個鐘

我5:30 PM花嘅10分鐘盯住screen省咗我幾日。

5. Navigation bugs係existential threats

我哋obsess over state management、data fetching、API optimization。

但broken navigation = blank screens = 「呢個platform係broken嘅。」

Users唔care你嘅RLS policies或者你嘅multi-tenant architecture。佢哋care㩒「View Results」會show results。呢個「technically works」同「actually finished」之間嘅gap喺我用AI build一個native iOS app嘅時候再次出現——Claude Code generate scaffold好快,但令users trust一個product嘅polish?嗰個係只有人類先deliver到嘅40%。

---

Pattern(For你嘅Multi-Tenant App)

如果你喺度build有hierarchical URLs嘅multi-tenant SaaS:

✅ Step 1: 喺layout level create一個Context provider

```typescript
<ClientContextProvider>
  {/* All tenant-scoped routes */}
</ClientContextProvider>
```

✅ Step 2: Build一個routing helper

```typescript
const { buildRoute } = useContextRoute();
navigate(buildRoute('agents/analysis/session/123'));
```

✅ Step 3: 永遠唔好hardcode routes

```typescript
// ❌ BAD
navigate('/analysis/session/123');

// ✅ GOOD
navigate(buildRoute('agents/analysis/session/123'));
```

✅ Step 4: Grep所有navigation calls

```bash
# Find every navigate() call
grep -r "navigate(" src/ > navigation_audit.txt

# Find hardcoded routes
grep -r "navigate('/" src/ | grep -v "buildRoute"
```

✅ Step 5: 用所有user types test

SME flow。Agency flow。每個button。每個link。冇blank pages。

---

結果

11月1日之前:

- 31個navigation bugs潛伏緊

- 每日5+個bug reports

- Agency users質疑platform stability

- 我:驚到唔敢ship新features

11月1日之後:

- 0個navigation bugs

- 0個navigation-related support tickets

- 為未來development建立咗pattern

- 我:有信心ship新agent routes

Development velocity:

- 加新routes:5分鐘(以前係30分鐘 +「會唔會break?」)

- Bug reports:0(以前每日5+)

- User trust:Restored(「Platform而家feel stable喇」)

我花喺fix呢啲bugs嘅6個鐘回報咗10×——減少support burden同restored user confidence。

---

點解我分享呢個

Multi-tenant navigation唔sexy。冇人會好似慶祝「shipped new feature」咁慶祝「6個鐘fix咗31個bugs」。

但如果你同我一樣喺度build multi-tenant SaaS,好似https://stratum.chandlernguyen.com/——一個for agencies嘅AI marketing platform——你會撞到呢個。可能唔係31個bugs。可能只係5個。但你會撞到。

當你撞到嘅時候,記住:

1. Context > Params for navigation state

2. Systematic > Individual fixes

3. Grep你成個codebase(你會搵到比你想嘅更多)

4. Claim victory之前用所有user types test

如果你發現自己盯住blank screen wondering你嘅context去咗邊,know that我亦喺同一個situation。:)

你ship過俾real users最painful嘅bug係咩——嗰種你只係因為有人話你知先發現嘅?我真心想聽。

祝好,

Chandler

STRAŦUM architecture series: 呢個navigation crisis係更大嘅multi-tenancy journey嘅一部分。佢由第2日build multi-tenancy開始,escalate到我要第67日rebuild成個schema,然後conclude於我發現database係correct但296x太慢

---

仲喺coding,仲喺learning,仲喺以31個為一組咁搵bugs。

https://stratum.chandlernguyen.com/request-invitation申請alpha access

---

P.S. ——報告第一個bug嘅user?佢冇整冇佢嘅interview data。Data save咗喺database。佢只係因為broken route而睇唔到。當我7:42 PM fix咗嘅時候,佢所有嘅work都仲喺度。嗰個小小嘅relief令6個鐘worth it。

---

繼續閱讀

我嘅旅程
聯繫
語言
偏好設定