Tam stack todo app: Next.js + Supabase + Vercel — 2 saatda
Next.js 14, Supabase və Vercel ilə tam işləyən todo app qur, deploy et və portfoliona əlavə et — hamısı 2 saatda, 0 manatla.
Tam stack todo app: Next.js + Supabase + Vercel — 2 saatda
Salam, developer! 👋
Bakıda işə müraciət edəndə HR-lar GitHub profilini açıb nəyə baxır bilirsən? Real layihələrə. Nə "Hello World"-lərə, nə də 47-ci calculator app-ə. Onlar istəyir ki, sən database ilə işləyə biləsən, deploy edə biləsən, full stack düşünə biləsən.
Bu gün sənə göstərəcəm ki, Next.js 14 + Supabase + Vercel üçlüsü ilə 2 saat ərzində tam işləyən bir todo app necə qurulur. Xərci? 0 AZN. Hamısının free tier-i var.
ABB Digital-da, Kapital Bank-ın tech komandasında, Pasha Holding-in IT departamentində — hər yerdə bu stack-ə tələbat var. LinkedIn-də "Next.js developer Baku" axtarışı etsən, 1500-3000 AZN arası maaşlı vakansiyalar görəcəksən. Gəl başlayaq.
Niyə bu stack?
Qısa cavab:
- Next.js 14 — React-in production-ready framework-u. Server Components, App Router, API routes — hamısı daxildir
- Supabase — Firebase alternativdir, amma PostgreSQL üzərində işləyir. SQL bilirsənsə, evindəsən
- Vercel — Next.js-in yaradıcılarının hosting platforması.
git pushedirsən, deploy olunur
Bu üç alət birlikdə sənə backend + frontend + hosting verir. DevOps bilmədən, server almadan.
Addım 1: Layihəni yarat (10 dəqiqə)
Terminalı aç və bu əmri yaz:
bashnpx create-next-app@latest todo-app --typescript --tailwind --app --src-dir cd todo-app npm install @supabase/supabase-js
Bu sənə TypeScript + Tailwind CSS + App Router ilə hazır Next.js layihəsi verir.
Addım 2: Supabase-də database qur (15 dəqiqə)
- supabase.com-a daxil ol, yeni layihə yarat
- SQL Editor-a keç və bu query-ni işlət:
sqlCREATE TABLE todos ( id UUID DEFAULT gen_random_uuid() PRIMARY KEY, title TEXT NOT NULL, is_completed BOOLEAN DEFAULT FALSE, created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() ); ALTER TABLE todos ENABLE ROW LEVEL SECURITY; CREATE POLICY "Public access" ON todos FOR ALL USING (true);
Bu sənə todos adlı table yaradır. Row Level Security (RLS) aktivdir — production-da bunu mütləq auth ilə bağlamalısan, amma demo üçün public açırıq.
Supabase dashboard-dan Project URL və anon key-i götür.
Addım 3: Supabase client-i konfiqurasiya et (5 dəqiqə)
Layihənin kökündə .env.local faylı yarat:
envNEXT_PUBLIC_SUPABASE_URL=https://xxxxx.supabase.co NEXT_PUBLIC_SUPABASE_ANON_KEY=eyJhbGciOiJIUzI1NiIs...
Sonra src/lib/supabase.ts faylını yarat:
typescriptimport { createClient } from '@supabase/supabase-js'; const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL!; const supabaseKey = process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!; export const supabase = createClient(supabaseUrl, supabaseKey);
Addım 4: Todo komponenti yaz (45 dəqiqə)
Bu layihənin əsas hissəsidir. src/app/page.tsx faylını tamamilə dəyiş:
tsx'use client'; import { useEffect, useState } from 'react'; import { supabase } from '@/lib/supabase'; interface Todo { id: string; title: string; is_completed: boolean; created_at: string; } export default function Home() { const [todos, setTodos] = useState<Todo[]>([]); const [newTodo, setNewTodo] = useState(''); const [loading, setLoading] = useState(true); useEffect(() => { fetchTodos(); }, []); async function fetchTodos() { const { data, error } = await supabase .from('todos') .select('*') .order('created_at', { ascending: false }); if (!error && data) setTodos(data); setLoading(false); } async function addTodo(e: React.FormEvent) { e.preventDefault(); if (!newTodo.trim()) return; const { data, error } = await supabase .from('todos') .insert([{ title: newTodo.trim() }]) .select(); if (!error && data) { setTodos([data[0], ...todos]); setNewTodo(''); } } async function toggleTodo(id: string, is_completed: boolean) { await supabase .from('todos') .update({ is_completed: !is_completed }) .eq('id', id); setTodos(todos.map(t => t.id === id ? { ...t, is_completed: !is_completed } : t )); } async function deleteTodo(id: string) { await supabase.from('todos').delete().eq('id', id); setTodos(todos.filter(t => t.id !== id)); } if (loading) return <p className="text-center mt-20">Yüklənir...</p>; return ( <main className="max-w-md mx-auto mt-16 px-4"> <h1 className="text-3xl font-bold mb-8 text-center"> 📋 Todo App </h1> <form onSubmit={addTodo} className="flex gap-2 mb-6"> <input value={newTodo} onChange={(e) => setNewTodo(e.target.value)} placeholder="Yeni tapşırıq əlavə et..." className="flex-1 border rounded-lg px-4 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500" /> <button type="submit" className="bg-blue-600 text-white px-6 py-2 rounded-lg hover:bg-blue-700 transition-colors" > Əlavə et </button> </form> <ul className="space-y-2"> {todos.map((todo) => ( <li key={todo.id} className="flex items-center justify-between bg-gray-50 rounded-lg px-4 py-3" > <div onClick={() => toggleTodo(todo.id, todo.is_completed)} className="flex items-center gap-3 cursor-pointer flex-1" > <span className={`w-5 h-5 rounded border-2 flex items-center justify-center ${todo.is_completed ? 'bg-green-500 border-green-500 text-white' : 'border-gray-300'}`} > {todo.is_completed && '✓'} </span> <span className={todo.is_completed ? 'line-through text-gray-400' : ''}> {todo.title} </span> </div> <button onClick={() => deleteTodo(todo.id)} className="text-red-400 hover:text-red-600 ml-2" > ✕ </button> </li> ))} </ul> {todos.length === 0 && ( <p className="text-center text-gray-400 mt-8"> Hələ tapşırıq yoxdur. Yuxarıdan əlavə et! 🚀 </p> )} </main> ); }
Bu kod sənə CRUD-un hamısını verir — Create, Read, Update (toggle), Delete.
Addım 5: Vercel-ə deploy et (15 dəqiqə)
bashgit init git add . git commit -m "initial: todo app with supabase"
GitHub-da yeni repo yarat, push et. Sonra:
- vercel.com-a daxil ol
- "Import Project" → GitHub reposunu seç
- Environment Variables bölməsində
.env.local-dakı dəyərləri əlavə et - "Deploy" basıb gözlə — 45 saniyə sonra app-in live olacaq
Sənin app-in artıq https://todo-app-xxxxx.vercel.app adresində işləyir. Bu linki CV-yə, LinkedIn-ə, GitHub README-yə yaz.
Növbəti addımlar: bunu portfolio layihəsindən real app-ə çevir
Bu bazanı qurduqdan sonra əlavə edə biləcəyin feature-lər:
- Supabase Auth — Google/GitHub login əlavə et
- Real-time —
supabase.channel()ilə canlı sync - Kategoriyalar — iş, şəxsi, öyrənmə kimi filtrlər
- Dark mode — Tailwind-in
dark:prefiksi ilə 15 dəqiqəyə hazırdır - PWA — next-pwa ilə telefona install olunan app-ə çevir
Hər bir əlavə feature sənin GitHub-dakı contribution graph-ını yaşıl edir. Bakıdakı recruiter-lər bunu görür.
Xərclər və rəqəmlər
| Xidmət | Free tier limiti | Kifayətdir? |
|---|---|---|
| Supabase | 500 MB database, 50K auth users | ✅ Bolca |
| Vercel | 100 GB bandwidth/ay | ✅ Bolca |
| GitHub | Limitsiz public repo | ✅ Həmişə |
Yəni 0 AZN xərcləyirsən. Üstəlik Supabase-in PostgreSQL-i olduğu üçün SQL biliklərin də inkişaf edir — interview-lərdə SQL sualı gələndə hazır olacaqsan.
Son söz
Bu todo app sadədir, bəli. Amma onu qurarkən öyrəndiyin şeylər — React hooks, TypeScript, PostgreSQL, API integration, deployment, environment variables, Git workflow — bunlar Bakıda hər bir tech şirkətin axtardığı bacarıqlardır.
2 saatını ayır, qur, deploy et, portfoliona əlavə et. Sabah müraciət etdiyin şirkətin CTO-su GitHub-ını açanda boş profil yox, işləyən app görəcək.
Sualın varsa — şərhlərdə yaz, birlikdə həll edərik. 🤝
Kod yazmağa davam et, Baku Stack ailəsi! 🚀
Oxşar məqalələr
Git Workflow — Komanda İşi Üçün Branch Strategiyası
Komandada işləyirsən və Git branch-ləri qarışır? Bu məqalədə real layihələrdə istifadə olunan workflow strategiyalarını praktiki nümunələrlə öyrən.
Stripe Ödənişlərini Next.js-ə İnteqrasiya Et: Tam Praktiki Bələdçi
Azərbaycandan Stripe ilə ödəniş qəbul etmək istəyirsən? Next.js App Router + Stripe Checkout ilə sıfırdan real ödəniş sistemi qururuq — kod, izah və praktiki məsləhətlərlə.
OpenAI API-ni Öz Tətbiqinizə Əlavə Etmək — Başlanğıc Bələdçi
GPT modelini öz layihənizə necə inteqrasiya edəcəyinizi praktiki kod nümunələri ilə addım-addım öyrənin. API key almaqdan tutmuş production-a qədər.