capturia ~ /careers/senior-dev
export async function POST(req: NextRequest) {
const { leadId, stage } = await req.json();
const { data } = await supabase
.from('client_contacts')
.update({ pipeline_stage: stage })
.eq('id', leadId).select().single();
await triggerWorkflow('stage_changed', data);
return NextResponse.json({ success: true });
}
 
const useLeadPipeline = (leadId: string) => {
return useQuery({
queryKey: ['pipeline', leadId],
queryFn: () => fetchPipelineData(leadId),
staleTime: 60_000,
});
};
 
export function StageCard({ stage }: Props) {
const { mutate } = useMutation({
mutationFn: updateStage,
onSuccess: () => invalidate(['pipeline']),
});
return <Card onClick={() => mutate(stage)} />;
}
export async function POST(req: NextRequest) {
const { leadId, stage } = await req.json();
const { data } = await supabase
.from('client_contacts')
.update({ pipeline_stage: stage })
.eq('id', leadId).select().single();
await triggerWorkflow('stage_changed', data);
return NextResponse.json({ success: true });
}
 
const useLeadPipeline = (leadId: string) => {
return useQuery({
queryKey: ['pipeline', leadId],
queryFn: () => fetchPipelineData(leadId),
staleTime: 60_000,
});
};
 
export function StageCard({ stage }: Props) {
const { mutate } = useMutation({
mutationFn: updateStage,
onSuccess: () => invalidate(['pipeline']),
});
return <Card onClick={() => mutate(stage)} />;
}
export async function POST(req: NextRequest) {
const { leadId, stage } = await req.json();
const { data } = await supabase
.from('client_contacts')
.update({ pipeline_stage: stage })
.eq('id', leadId).select().single();
await triggerWorkflow('stage_changed', data);
return NextResponse.json({ success: true });
}
 
const useLeadPipeline = (leadId: string) => {
return useQuery({
queryKey: ['pipeline', leadId],
queryFn: () => fetchPipelineData(leadId),
staleTime: 60_000,
});
};
 
export function StageCard({ stage }: Props) {
const { mutate } = useMutation({
mutationFn: updateStage,
onSuccess: () => invalidate(['pipeline']),
});
return <Card onClick={() => mutate(stage)} />;
}
export async function POST(req: NextRequest) {
const { leadId, stage } = await req.json();
const { data } = await supabase
.from('client_contacts')
.update({ pipeline_stage: stage })
.eq('id', leadId).select().single();
await triggerWorkflow('stage_changed', data);
return NextResponse.json({ success: true });
}
 
const useLeadPipeline = (leadId: string) => {
return useQuery({
queryKey: ['pipeline', leadId],
queryFn: () => fetchPipelineData(leadId),
staleTime: 60_000,
});
};
 
export function StageCard({ stage }: Props) {
const { mutate } = useMutation({
mutationFn: updateStage,
onSuccess: () => invalidate(['pipeline']),
});
return <Card onClick={() => mutate(stage)} />;
}
export async function POST(req: NextRequest) {
const { leadId, stage } = await req.json();
const { data } = await supabase
.from('client_contacts')
.update({ pipeline_stage: stage })
.eq('id', leadId).select().single();
await triggerWorkflow('stage_changed', data);
return NextResponse.json({ success: true });
}
 
const useLeadPipeline = (leadId: string) => {
return useQuery({
queryKey: ['pipeline', leadId],
queryFn: () => fetchPipelineData(leadId),
staleTime: 60_000,
});
};
 
export function StageCard({ stage }: Props) {
const { mutate } = useMutation({
mutationFn: updateStage,
onSuccess: () => invalidate(['pipeline']),
});
return <Card onClick={() => mutate(stage)} />;
}
export async function POST(req: NextRequest) {
const { leadId, stage } = await req.json();
const { data } = await supabase
.from('client_contacts')
.update({ pipeline_stage: stage })
.eq('id', leadId).select().single();
await triggerWorkflow('stage_changed', data);
return NextResponse.json({ success: true });
}
 
const useLeadPipeline = (leadId: string) => {
return useQuery({
queryKey: ['pipeline', leadId],
queryFn: () => fetchPipelineData(leadId),
staleTime: 60_000,
});
};
 
export function StageCard({ stage }: Props) {
const { mutate } = useMutation({
mutationFn: updateStage,
onSuccess: () => invalidate(['pipeline']),
});
return <Card onClick={() => mutate(stage)} />;
}
export async function POST(req: NextRequest) {
const { leadId, stage } = await req.json();
const { data } = await supabase
.from('client_contacts')
.update({ pipeline_stage: stage })
.eq('id', leadId).select().single();
await triggerWorkflow('stage_changed', data);
return NextResponse.json({ success: true });
}
 
const useLeadPipeline = (leadId: string) => {
return useQuery({
queryKey: ['pipeline', leadId],
queryFn: () => fetchPipelineData(leadId),
staleTime: 60_000,
});
};
 
export function StageCard({ stage }: Props) {
const { mutate } = useMutation({
mutationFn: updateStage,
onSuccess: () => invalidate(['pipeline']),
});
return <Card onClick={() => mutate(stage)} />;
}
export async function POST(req: NextRequest) {
const { leadId, stage } = await req.json();
const { data } = await supabase
.from('client_contacts')
.update({ pipeline_stage: stage })
.eq('id', leadId).select().single();
await triggerWorkflow('stage_changed', data);
return NextResponse.json({ success: true });
}
 
const useLeadPipeline = (leadId: string) => {
return useQuery({
queryKey: ['pipeline', leadId],
queryFn: () => fetchPipelineData(leadId),
staleTime: 60_000,
});
};
 
export function StageCard({ stage }: Props) {
const { mutate } = useMutation({
mutationFn: updateStage,
onSuccess: () => invalidate(['pipeline']),
});
return <Card onClick={() => mutate(stage)} />;
}
export async function POST(req: NextRequest) {
const { leadId, stage } = await req.json();
const { data } = await supabase
.from('client_contacts')
.update({ pipeline_stage: stage })
.eq('id', leadId).select().single();
await triggerWorkflow('stage_changed', data);
return NextResponse.json({ success: true });
}
 
const useLeadPipeline = (leadId: string) => {
return useQuery({
queryKey: ['pipeline', leadId],
queryFn: () => fetchPipelineData(leadId),
staleTime: 60_000,
});
};
 
export function StageCard({ stage }: Props) {
const { mutate } = useMutation({
mutationFn: updateStage,
onSuccess: () => invalidate(['pipeline']),
});
return <Card onClick={() => mutate(stage)} />;
}
export async function POST(req: NextRequest) {
const { leadId, stage } = await req.json();
const { data } = await supabase
.from('client_contacts')
.update({ pipeline_stage: stage })
.eq('id', leadId).select().single();
await triggerWorkflow('stage_changed', data);
return NextResponse.json({ success: true });
}
 
const useLeadPipeline = (leadId: string) => {
return useQuery({
queryKey: ['pipeline', leadId],
queryFn: () => fetchPipelineData(leadId),
staleTime: 60_000,
});
};
 
export function StageCard({ stage }: Props) {
const { mutate } = useMutation({
mutationFn: updateStage,
onSuccess: () => invalidate(['pipeline']),
});
return <Card onClick={() => mutate(stage)} />;
}
export async function POST(req: NextRequest) {
const { leadId, stage } = await req.json();
const { data } = await supabase
.from('client_contacts')
.update({ pipeline_stage: stage })
.eq('id', leadId).select().single();
await triggerWorkflow('stage_changed', data);
return NextResponse.json({ success: true });
}
 
const useLeadPipeline = (leadId: string) => {
return useQuery({
queryKey: ['pipeline', leadId],
queryFn: () => fetchPipelineData(leadId),
staleTime: 60_000,
});
};
 
export function StageCard({ stage }: Props) {
const { mutate } = useMutation({
mutationFn: updateStage,
onSuccess: () => invalidate(['pipeline']),
});
return <Card onClick={() => mutate(stage)} />;
}
export async function POST(req: NextRequest) {
const { leadId, stage } = await req.json();
const { data } = await supabase
.from('client_contacts')
.update({ pipeline_stage: stage })
.eq('id', leadId).select().single();
await triggerWorkflow('stage_changed', data);
return NextResponse.json({ success: true });
}
 
const useLeadPipeline = (leadId: string) => {
return useQuery({
queryKey: ['pipeline', leadId],
queryFn: () => fetchPipelineData(leadId),
staleTime: 60_000,
});
};
 
export function StageCard({ stage }: Props) {
const { mutate } = useMutation({
mutationFn: updateStage,
onSuccess: () => invalidate(['pipeline']),
});
return <Card onClick={() => mutate(stage)} />;
}
$NOW HIRING

Senior Full-Stack Dev WantedCome build what's next.

Discover the role
system-status
$
Edge Functions in prod
Active integrations
Framework
TypeScript mode
Production uptime
Remote
$
Next.jsReactTypeScriptSupabaseVercelTailwind CSSn8nAnthropicOpenAIGitHub

Theproductissolid,clientsarehere,theengineeringteamisgrowing.We'relookingforaseniordevtotakeownershipofthearchitectureandhelpusreachthenextlevel.

D
Dany Therrien
Founder, Capturia
🏗️

A real product, not a prototype

65+ edge functions in production, OAuth integrations, automated workflows, clients using the system every day. You're not walking into a greenfield — you're walking into something that runs.

🔑

Your decisions actually matter

You propose an architecture, we discuss it, and it ships. Nobody makes the call for you. This isn't just a buzzword in the job posting — the ownership is real.

📲

The founder is one message away

No 12-person sprint planning, no PM sitting between you and decisions. A question? Direct message. An answer? 24h max. It's that simple.

The production stack

Everything below runs in prod today — it's not a wish list.

Frontend
Next.js 16React 19TypeScript strictTailwind CSS v4Framer MotionRadix UI
Backend
SupabaseEdge FunctionsPostgreSQL + RLSTanStack QueryStripe ConnectReact Email + Resend
AI & Automation
Claude CodeOpenAI APIAnthropic SDKn8n / ZapierTwilioAssemblyAI
Infra
VercelSupabase CLIGitHub (main only)MCP Tools

$ If you already know these tools, you'll be productive from week one.

How we know it's working

No annual performance review with made-up metrics. Five concrete things we look at.

kpis.test.ts
$

What a typical day looks like

No endless meetings, no pointless standups. Real dev work.

$ git log --oneline --graph
*
9:00am

System check

You check Vercel, Supabase logs, dashboards. You don't need anyone to tell you if something broke — you see it yourself.

*
9:30am

Architecture before code

You read the existing code, identify the impacts of what you're about to do. Only then do you start coding.

*
11:30am

DB + Backend

MCP migrations, RLS policies, data structure. You make these decisions without asking permission.

*
2:00pm

Code review

You review the team's code and the team reviews yours. Not just what's wrong — why it's wrong and how to do it better.

*
3:30pm

Validate + deploy

npm run validate. Zero warnings. You push to production knowing exactly what you're shipping.

*
4:30pm

Founder sync

It's not a formal meeting. Three messages to align on the next priority and you're done.

Are you the right person?

We'll be upfront — here's exactly what we're looking for.

What we absolutely need

  • 5+ years in full-stack development with React/Next.js and a solid backend
  • You've taken ownership of an existing codebase before — not just closed tickets
  • Strict TypeScript without any — interfaces, generics, explicit types
  • You make architecture decisions and know how to defend them when challenged
  • Real PostgreSQL: migrations, constraints, row-level security

A big plus

  • Experience with Supabase (Auth, RLS, Edge Functions, Realtime)
  • Complex OAuth integrations (Zoom, Google, Stripe Connect)
  • Multi-tenant SaaS with real paying clients
  • Experience guiding or reviewing other developers

Red flags

You ship code without reading what already exists
You make decisions without evaluating production impact
You wait to be told what to do instead of taking initiative
No consistent patterns — every problem, you start from scratch

CANDIDATURE

esc
F1
F2
F3
F4
F5
F6
F7
F8
F9
F10
F11
F12
~`
!1
@2
#3
$4
%5
^6
&7
*8
(9
)0
_
+=
delete
tab
Q
W
E
R
T
Y
U
I
O
P
{[
}]
|\
caps lock
A
S
D
F
G
H
J
K
L
:;
"'
return
shift
Z
X
C
V
B
N
M
<,
>.
?/
shift
fn
control
option
command
command
option
APPLICATION

Sound like you?

Salary based on your experience and skills. 100% remote, based in Quebec.

application.tsx
Show us who you are

Your background, a project you're proud of, and how you think through real challenges.

01Resume / CV

Your up-to-date resume — we want to see your background, projects, and what you've built.

02Portfolio(optional)

A project you fully owned. Not just contributed to — owned.

Your information is confidential and will never be shared.