Skip to content

Commit b16ee20

Browse files
committed
feat: enhance BETTER_AUTH_URL handling for Railway PR environments and improve application detail fetching logic
1 parent 7092b05 commit b16ee20

4 files changed

Lines changed: 44 additions & 30 deletions

File tree

ARCHITECTURE.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -295,7 +295,9 @@ Variables are configured in the Railway dashboard or via `railway variables`. Se
295295
| `S3_REGION` | `${{Bucket.REGION}}` |
296296
| `S3_FORCE_PATH_STYLE` | `false` |
297297
| `BETTER_AUTH_SECRET` | Manual (sealed) |
298-
| `BETTER_AUTH_URL` | `https://applirank.com` |
298+
| `BETTER_AUTH_URL` | Production: `https://applirank.com` · PR/preview: `https://${{RAILWAY_PUBLIC_DOMAIN}}` |
299+
300+
For zero manual PR setup, define `BETTER_AUTH_URL` as `https://${{RAILWAY_PUBLIC_DOMAIN}}` in your Railway preview/PR environment (or shared variables scoped to previews).
299301
## Local Development Services
300302

301303
| Service | URL | Purpose |

app/pages/dashboard/jobs/[id]/swipe.vue

Lines changed: 28 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,12 @@ type SwipeApplicationDetail = {
159159
responses: SwipeResponse[]
160160
}
161161
162-
const currentApplicationId = computed(() => currentSummary.value?.id ?? '')
162+
const currentApplicationId = ref('')
163+
164+
watch(currentSummary, (summary) => {
165+
if (!summary?.id) return
166+
currentApplicationId.value = summary.id
167+
}, { immediate: true })
163168
164169
const {
165170
data: currentApplication,
@@ -168,17 +173,19 @@ const {
168173
} = useFetch<SwipeApplicationDetail | null>(
169174
() => `/api/applications/${currentApplicationId.value}`,
170175
{
171-
key: computed(() => `swipe-application-${currentApplicationId.value || 'none'}`),
176+
key: computed(() => `swipe-application-${currentApplicationId.value}`),
172177
immediate: false,
173178
headers: useRequestHeaders(['cookie']),
174179
},
175180
)
176181
182+
const resolvedCurrentApplication = computed(() => {
183+
if (!currentApplication.value) return null
184+
return currentApplication.value.id === currentApplicationId.value ? currentApplication.value : null
185+
})
186+
177187
watch(currentApplicationId, async (id) => {
178-
if (!id) {
179-
currentApplication.value = null
180-
return
181-
}
188+
if (!id) return
182189
183190
await executeDetailFetch()
184191
}, { immediate: true })
@@ -531,9 +538,9 @@ const isLoading = computed(() => {
531538
<Mail class="size-3.5" />
532539
{{ currentSummary.candidateEmail }}
533540
</span>
534-
<span v-if="currentApplication?.candidate.phone" class="inline-flex items-center gap-1.5">
541+
<span v-if="resolvedCurrentApplication?.candidate.phone" class="inline-flex items-center gap-1.5">
535542
<Phone class="size-3.5" />
536-
{{ currentApplication.candidate.phone }}
543+
{{ resolvedCurrentApplication.candidate.phone }}
537544
</span>
538545
</div>
539546
</div>
@@ -568,28 +575,28 @@ const isLoading = computed(() => {
568575
>
569576
Documents
570577
<span
571-
v-if="currentApplication?.candidate.documents?.length"
578+
v-if="resolvedCurrentApplication?.candidate.documents?.length"
572579
class="ml-1 text-xs text-surface-400"
573580
>
574-
({{ currentApplication.candidate.documents.length }})
581+
({{ resolvedCurrentApplication.candidate.documents.length }})
575582
</span>
576583
</button>
577584
<button
578-
v-if="currentApplication?.responses?.length"
585+
v-if="resolvedCurrentApplication?.responses?.length"
579586
class="cursor-pointer px-3 py-2.5 text-sm font-medium transition-colors border-b-2 -mb-px"
580587
:class="detailTab === 'responses'
581588
? 'border-brand-600 text-brand-600 dark:border-brand-400 dark:text-brand-400'
582589
: 'border-transparent text-surface-500 hover:text-surface-700 hover:border-surface-300 dark:hover:text-surface-300'"
583590
@click="detailTab = 'responses'"
584591
>
585-
Responses ({{ currentApplication.responses.length }})
592+
Responses ({{ resolvedCurrentApplication.responses.length }})
586593
</button>
587594
</div>
588595
</div>
589596

590597
<!-- Detail content -->
591598
<div class="flex-1 overflow-y-auto bg-surface-50 dark:bg-surface-950 p-6">
592-
<div v-if="detailFetchStatus === 'pending'" class="py-8 text-center text-sm text-surface-400">
599+
<div v-if="detailFetchStatus === 'pending' && !resolvedCurrentApplication" class="py-8 text-center text-sm text-surface-400">
593600
Loading details…
594601
</div>
595602

@@ -614,10 +621,10 @@ const isLoading = computed(() => {
614621
{{ currentSummary.candidateEmail }}
615622
</dd>
616623
</div>
617-
<div v-if="currentApplication?.candidate.phone">
624+
<div v-if="resolvedCurrentApplication?.candidate.phone">
618625
<dt class="text-surface-400">Phone</dt>
619626
<dd class="text-surface-700 dark:text-surface-200 font-medium">
620-
{{ currentApplication.candidate.phone }}
627+
{{ resolvedCurrentApplication.candidate.phone }}
621628
</dd>
622629
</div>
623630
<div>
@@ -683,9 +690,9 @@ const isLoading = computed(() => {
683690

684691
<!-- DOCUMENTS TAB -->
685692
<div v-else-if="detailTab === 'documents'" class="space-y-3 max-w-3xl">
686-
<div v-if="currentApplication?.candidate.documents?.length" class="space-y-2.5">
693+
<div v-if="resolvedCurrentApplication?.candidate.documents?.length" class="space-y-2.5">
687694
<div
688-
v-for="doc in currentApplication.candidate.documents"
695+
v-for="doc in resolvedCurrentApplication.candidate.documents"
689696
:key="doc.id"
690697
class="flex flex-wrap items-center justify-between gap-2 rounded-lg border border-surface-200 bg-white px-4 py-3 dark:border-surface-800 dark:bg-surface-900"
691698
>
@@ -728,9 +735,9 @@ const isLoading = computed(() => {
728735

729736
<!-- RESPONSES TAB -->
730737
<div v-else-if="detailTab === 'responses'" class="space-y-3 max-w-3xl">
731-
<div v-if="currentApplication?.responses?.length" class="space-y-2.5">
738+
<div v-if="resolvedCurrentApplication?.responses?.length" class="space-y-2.5">
732739
<div
733-
v-for="response in currentApplication.responses"
740+
v-for="response in resolvedCurrentApplication.responses"
734741
:key="response.id"
735742
class="rounded-lg border border-surface-200 bg-white p-4 dark:border-surface-800 dark:bg-surface-900"
736743
>
@@ -808,13 +815,13 @@ const isLoading = computed(() => {
808815
<div class="flex items-center justify-between">
809816
<dt class="text-surface-500 dark:text-surface-400">Documents</dt>
810817
<dd class="text-surface-700 dark:text-surface-200 text-xs">
811-
{{ currentApplication?.candidate.documents?.length ?? 0 }}
818+
{{ resolvedCurrentApplication?.candidate.documents?.length ?? 0 }}
812819
</dd>
813820
</div>
814821
<div class="flex items-center justify-between">
815822
<dt class="text-surface-500 dark:text-surface-400">Responses</dt>
816823
<dd class="text-surface-700 dark:text-surface-200 text-xs">
817-
{{ currentApplication?.responses?.length ?? 0 }}
824+
{{ resolvedCurrentApplication?.responses?.length ?? 0 }}
818825
</dd>
819826
</div>
820827
</dl>

server/utils/auth.ts

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,19 +21,20 @@ function resolveBetterAuthUrl(): string {
2121
return explicitUrl
2222
}
2323

24-
const prNumber = env.RAILWAY_GIT_PR_NUMBER?.trim()
25-
if (prNumber) {
26-
const previewUrl = `https://applirank-applirank-pr-${prNumber}.up.railway.app`
27-
console.info(`[Applirank] Using Railway PR-derived BETTER_AUTH_URL: ${previewUrl}`)
28-
return previewUrl
29-
}
30-
3124
if (railwayDomain) {
3225
const previewUrl = `https://${railwayDomain}`
3326
console.info(`[Applirank] Using Railway public-domain BETTER_AUTH_URL: ${previewUrl}`)
3427
return previewUrl
3528
}
3629

30+
const prNumber = env.RAILWAY_GIT_PR_NUMBER?.trim()
31+
if (prNumber) {
32+
console.warn(
33+
`[Applirank] Railway PR number detected (${prNumber}) but RAILWAY_PUBLIC_DOMAIN is missing. ` +
34+
'Set BETTER_AUTH_URL explicitly or ensure Railway generated domains are enabled.',
35+
)
36+
}
37+
3738
if (explicitUrl) {
3839
console.info('[Applirank] Using explicit BETTER_AUTH_URL in Railway PR/preview environment')
3940
return explicitUrl

server/utils/env.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,11 @@ const envSchema = z
6565
GITHUB_FEEDBACK_REPO: emptyToUndefined.pipe(z.string().regex(/^[^/]+\/[^/]+$/, 'Must be in "owner/repo" format')).optional(),
6666
})
6767
.superRefine((data, ctx) => {
68-
const isPreview = isRailwayPreviewEnvironment(data.RAILWAY_ENVIRONMENT_NAME)
68+
const hasPreviewDomain = data.RAILWAY_PUBLIC_DOMAIN
69+
? data.RAILWAY_PUBLIC_DOMAIN.toLowerCase().includes('-pr-')
70+
: false
71+
const hasPrNumber = !!data.RAILWAY_GIT_PR_NUMBER
72+
const isPreview = isRailwayPreviewEnvironment(data.RAILWAY_ENVIRONMENT_NAME) || hasPreviewDomain || hasPrNumber
6973

7074
if (!isPreview && !data.BETTER_AUTH_URL) {
7175
ctx.addIssue({

0 commit comments

Comments
 (0)