Bug deep link di aplikasi hasil vibe coding biasanya dimulai dari masalah input yang membosankan: user ID yang malformed, URL campaign yang sudah usang, nilai enum yang hilang di payload push. Lalu aplikasi memperlakukan input itu sebagai sesuatu yang tepercaya dan sebuah screen crash jauh di dalam happy-path logic.

Setiap parameter URL adalah user input. Deep link, payload push notification, shared URL, QR code - semuanya tidak tepercaya. Saat Anda melakukan vibe coding dengan Cursor, Claude Code menghasilkan happy path dengan indah. Ia tidak menghasilkan paranoid path kecuali Anda memintanya. Ia berasumsi. Production menghukum asumsi.

Validasi Zod di Boundary Route

Validasi params tepat saat mereka masuk ke aplikasi. Setelah validasi, sisa kode Anda bekerja dengan nilai yang bertipe dan dijamin aman:

// app/(app)/profile.tsx
// Validate at the gate. Everything past this point is typed.

import { useLocalSearchParams } from 'expo-router'
import { z } from 'zod'

const profileParamsSchema = z.object({
  section: z
    .enum(['overview', 'security', 'preferences'])
    .default('overview'),
  userId: z.string().uuid().optional(),
})

type ProfileParams = z.infer<typeof profileParamsSchema>

export default function ProfileScreen() {
  const raw = useLocalSearchParams()
  const result = profileParamsSchema.safeParse(raw)

  if (!result.success) {
    return <ErrorScreen message='Invalid profile parameters' />
  }

  const { section, userId } = result.data
  return <ProfileContent section={section} userId={userId} />
}

ProfileContent menerima section dan userId sebagai nilai yang sudah bertipe dengan benar. Ia tidak tahu apa itu useLocalSearchParams. Ia tidak memvalidasi. Ia hanya menerima data yang baik. Begitulah cara membangun aplikasi hasil vibe coding di mana fitur buatan AI tidak rusak ketika dunia nyata mengirimkan data sampah.

+native-intent: Tolak URL Berbahaya Sebelum Masuk

Expo Router memberi Anda +native-intent.tsx untuk menangani path native yang masuk dan mungkin malformed, stale, atau berbahaya. File ini berjalan sebelum providers Anda mount. File ini hanya boleh menulis ulang path dan menolak input buruk:

// app/+native-intent.tsx
// This is your firewall, not your business logic.

export function redirectSystemPath({
  path,
}: {
  path: string
}) {
  // Reject paths with suspicious patterns
  if (path.includes('..') || path.includes('//')) {
    return '/'
  }

  // Migrate old URL format to new format
  if (path.startsWith('/user/')) {
    const userId = path.replace('/user/', '')
    if (z.string().uuid().safeParse(userId).success) {
      return `/profile?userId=${userId}`
    }
    return '/'
  }

  return path
}

Insight utamanya: +native-intent tidak bisa mengecek apakah pengguna sudah login. File ini hanya boleh men-sanitize path. Otorisasi bisnis berada di route guards, bukan di sini.

Typed Routes: Tangkap Error Saat Compile Time

Aktifkan typedRoutes di config Anda dan tangkap nama route yang salah eja sebelum sampai ke pengguna:

// app.config.ts
{
  experiments: {
    typedRoutes: true,
  }
}

// Now the router validates at compile time:
router.push('/profile')         // OK
router.push('/profle')          // TypeScript error
router.push({
  pathname: '/profile',
  params: { section: 'overview' },
})  // OK

Typed routes menangkap nama yang salah eja. Validasi Zod menangkap parameter yang buruk. Di antara keduanya, Anda punya jaring pengaman yang bahkan tidak dimiliki banyak web router.

Autotomy Expo Starter Pack sudah menyertakan pattern validasi Zod, konfigurasi typed routes, dan handler +native-intent. Deep links Anda berfungsi. Pengguna Anda tidak crash.