├── .vscode └── settings.json ├── .github ├── FUNDING.yml ├── ISSUE_TEMPLATE │ └── bug_report.md └── PULL_REQUEST_TEMPLATE.md ├── .eslintrc.json ├── public ├── icon1.png ├── favicon.ico ├── og-image.png ├── apple-icon.png ├── bolt-dark.png ├── bolt-light.png ├── dark-hero.png ├── icon-black.png ├── icon-white.png ├── light-hero.png ├── logo-dark.png ├── logo-light.png ├── black-orchid.png ├── cartographer.png ├── web-app-manifest-192x192.png ├── web-app-manifest-512x512.png ├── github.svg └── google.svg ├── postcss.config.js ├── app ├── test │ └── [foo] │ │ └── page.tsx ├── api │ └── fetch-meta │ │ └── route.ts ├── dashboard │ ├── layout.tsx │ └── settings │ │ └── page.tsx ├── layout.tsx ├── privacy │ └── page.tsx ├── terms │ └── page.tsx ├── share │ └── [token] │ │ └── page.tsx └── globals.css ├── supabase └── migrations │ ├── 20240710120000_add_public_share_token_to_projects.sql │ ├── 20250101000001_add_is_done_to_tasks.sql │ ├── 20250621183000_add_slug_to_projects.sql │ ├── 20240710180000_create_bookmarks_table.sql │ ├── 20250731160000_fix_user_search_auth.sql │ ├── 20250621175727_fierce_butterfly.sql │ ├── 20250722000000_fix_profiles_security.sql │ ├── 20250722000001_check_and_fix_rls.sql │ ├── 20250621180641_misty_math.sql │ ├── 20250621180724_heavy_darkness.sql │ ├── 20250621182708_precious_credit.sql │ ├── 20250621182413_blue_delta.sql │ └── 20250621182625_patient_boat.sql ├── .dockerignore ├── lib ├── utils.ts ├── stripe.ts ├── types.ts ├── supabase.ts └── database-example.ts ├── components ├── ui │ ├── aspect-ratio.tsx │ ├── skeleton.tsx │ ├── collapsible.tsx │ ├── label.tsx │ ├── input.tsx │ ├── textarea.tsx │ ├── separator.tsx │ ├── progress.tsx │ ├── toaster.tsx │ ├── sonner.tsx │ ├── checkbox.tsx │ ├── slider.tsx │ ├── badge.tsx │ ├── switch.tsx │ ├── hover-card.tsx │ ├── tooltip.tsx │ ├── popover.tsx │ ├── avatar.tsx │ ├── radio-group.tsx │ ├── toggle.tsx │ ├── alert.tsx │ ├── scroll-area.tsx │ ├── resizable.tsx │ ├── toggle-group.tsx │ ├── tabs.tsx │ ├── card.tsx │ ├── accordion.tsx │ ├── button.tsx │ ├── input-otp.tsx │ ├── calendar.tsx │ ├── breadcrumb.tsx │ ├── table.tsx │ ├── pagination.tsx │ ├── drawer.tsx │ ├── dialog.tsx │ ├── sheet.tsx │ └── form.tsx ├── theme-provider.tsx ├── customized │ └── avatar │ │ └── avatar-12.tsx ├── user-provider.tsx └── section-cards.tsx ├── scripts ├── vercel-build.sh ├── init-db.sql └── setup-postgres.js ├── next.config.js ├── vercel.json ├── docker-compose.yml ├── components.json ├── hooks ├── use-mobile.tsx ├── use-mouse.ts └── use-toast.ts ├── .gitignore ├── tsconfig.json ├── Dockerfile ├── SECURITY.md ├── src ├── stripe-config.ts └── components │ ├── ui │ └── kibo-ui │ │ ├── announcement │ │ └── index.tsx │ │ └── status │ │ └── index.tsx │ ├── magicui │ ├── shine-border.tsx │ ├── text-reveal.tsx │ ├── border-beam.tsx │ └── magic-card.tsx │ └── eldoraui │ └── gitstarbutton.tsx ├── LICENSE ├── docker-compose.postgres.yml ├── env.example ├── .env.example ├── README_POSTGRES.md ├── CONTRIBUTING.md ├── tailwind.config.ts ├── package.json └── README-DEPLOYMENT.md /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | } -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | 2 | github: [uaghazade1] 3 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "next/core-web-vitals" 3 | } 4 | -------------------------------------------------------------------------------- /public/icon1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kanba-co/kanba/HEAD/public/icon1.png -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kanba-co/kanba/HEAD/public/favicon.ico -------------------------------------------------------------------------------- /public/og-image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kanba-co/kanba/HEAD/public/og-image.png -------------------------------------------------------------------------------- /public/apple-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kanba-co/kanba/HEAD/public/apple-icon.png -------------------------------------------------------------------------------- /public/bolt-dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kanba-co/kanba/HEAD/public/bolt-dark.png -------------------------------------------------------------------------------- /public/bolt-light.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kanba-co/kanba/HEAD/public/bolt-light.png -------------------------------------------------------------------------------- /public/dark-hero.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kanba-co/kanba/HEAD/public/dark-hero.png -------------------------------------------------------------------------------- /public/icon-black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kanba-co/kanba/HEAD/public/icon-black.png -------------------------------------------------------------------------------- /public/icon-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kanba-co/kanba/HEAD/public/icon-white.png -------------------------------------------------------------------------------- /public/light-hero.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kanba-co/kanba/HEAD/public/light-hero.png -------------------------------------------------------------------------------- /public/logo-dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kanba-co/kanba/HEAD/public/logo-dark.png -------------------------------------------------------------------------------- /public/logo-light.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kanba-co/kanba/HEAD/public/logo-light.png -------------------------------------------------------------------------------- /public/black-orchid.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kanba-co/kanba/HEAD/public/black-orchid.png -------------------------------------------------------------------------------- /public/cartographer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kanba-co/kanba/HEAD/public/cartographer.png -------------------------------------------------------------------------------- /public/web-app-manifest-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kanba-co/kanba/HEAD/public/web-app-manifest-192x192.png -------------------------------------------------------------------------------- /public/web-app-manifest-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kanba-co/kanba/HEAD/public/web-app-manifest-512x512.png -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | }; 7 | -------------------------------------------------------------------------------- /app/test/[foo]/page.tsx: -------------------------------------------------------------------------------- 1 | export default function TestFooPage({ params }: { params: { foo: string } }) { 2 | return
Test dynamic route: {params.foo}
; 3 | } -------------------------------------------------------------------------------- /supabase/migrations/20240710120000_add_public_share_token_to_projects.sql: -------------------------------------------------------------------------------- 1 | -- Proje public paylaşım token alanı 2 | ALTER TABLE projects ADD COLUMN public_share_token TEXT UNIQUE; -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .next 3 | .git 4 | .gitignore 5 | Dockerfile 6 | docker-compose.yml 7 | README.md 8 | README-DEPLOYMENT.md 9 | *.log 10 | .env* 11 | .vscode -------------------------------------------------------------------------------- /lib/utils.ts: -------------------------------------------------------------------------------- 1 | import { clsx, type ClassValue } from 'clsx'; 2 | import { twMerge } from 'tailwind-merge'; 3 | 4 | export function cn(...inputs: ClassValue[]) { 5 | return twMerge(clsx(inputs)); 6 | } 7 | -------------------------------------------------------------------------------- /components/ui/aspect-ratio.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | 3 | import * as AspectRatioPrimitive from '@radix-ui/react-aspect-ratio'; 4 | 5 | const AspectRatio = AspectRatioPrimitive.Root; 6 | 7 | export { AspectRatio }; 8 | -------------------------------------------------------------------------------- /scripts/vercel-build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Vercel build script 4 | echo "Starting Vercel build..." 5 | 6 | # Generate Prisma client 7 | echo "Generating Prisma client..." 8 | npx prisma generate 9 | 10 | # Build Next.js application 11 | echo "Building Next.js application..." 12 | npm run build 13 | 14 | echo "Build completed successfully!" -------------------------------------------------------------------------------- /components/ui/skeleton.tsx: -------------------------------------------------------------------------------- 1 | import { cn } from "@/lib/utils" 2 | 3 | function Skeleton({ 4 | className, 5 | ...props 6 | }: React.HTMLAttributes) { 7 | return ( 8 |
12 | ) 13 | } 14 | 15 | export { Skeleton } 16 | -------------------------------------------------------------------------------- /components/theme-provider.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | 3 | import * as React from 'react'; 4 | import { ThemeProvider as NextThemesProvider } from 'next-themes'; 5 | import { type ThemeProviderProps } from 'next-themes/dist/types'; 6 | 7 | export function ThemeProvider({ children, ...props }: ThemeProviderProps) { 8 | return {children}; 9 | } -------------------------------------------------------------------------------- /next.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = { 3 | eslint: { 4 | ignoreDuringBuilds: true, 5 | }, 6 | images: { unoptimized: true }, 7 | experimental: { 8 | serverComponentsExternalPackages: ['@prisma/client'], 9 | }, 10 | typescript: { 11 | ignoreBuildErrors: true, 12 | }, 13 | }; 14 | 15 | module.exports = nextConfig; -------------------------------------------------------------------------------- /components/ui/collapsible.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | 3 | import * as CollapsiblePrimitive from '@radix-ui/react-collapsible'; 4 | 5 | const Collapsible = CollapsiblePrimitive.Root; 6 | 7 | const CollapsibleTrigger = CollapsiblePrimitive.CollapsibleTrigger; 8 | 9 | const CollapsibleContent = CollapsiblePrimitive.CollapsibleContent; 10 | 11 | export { Collapsible, CollapsibleTrigger, CollapsibleContent }; 12 | -------------------------------------------------------------------------------- /vercel.json: -------------------------------------------------------------------------------- 1 | { 2 | "buildCommand": "npm run vercel-build", 3 | "installCommand": "npm install", 4 | "framework": "nextjs", 5 | "functions": { 6 | "app/api/**/*.ts": { 7 | "maxDuration": 30 8 | } 9 | }, 10 | "env": { 11 | "PRISMA_GENERATE_DATAPROXY": "true" 12 | }, 13 | "build": { 14 | "env": { 15 | "PRISMA_GENERATE_DATAPROXY": "true" 16 | } 17 | }, 18 | "regions": ["iad1"], 19 | "outputDirectory": ".next" 20 | } -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3.8' 2 | services: 3 | web: 4 | build: . 5 | container_name: kanban-app 6 | ports: 7 | - '3000:3000' 8 | environment: 9 | - NEXT_PUBLIC_SUPABASE_URL=${NEXT_PUBLIC_SUPABASE_URL} 10 | - NEXT_PUBLIC_SUPABASE_ANON_KEY=${NEXT_PUBLIC_SUPABASE_ANON_KEY} 11 | # - SUPABASE_SERVICE_ROLE_KEY=${SUPABASE_SERVICE_ROLE_KEY} # (opsiyonel, gerekirse ekle) 12 | restart: unless-stopped 13 | env_file: 14 | - .env.local -------------------------------------------------------------------------------- /components.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://ui.shadcn.com/schema.json", 3 | "style": "default", 4 | "rsc": true, 5 | "tsx": true, 6 | "tailwind": { 7 | "config": "tailwind.config.ts", 8 | "css": "app/globals.css", 9 | "baseColor": "neutral", 10 | "cssVariables": true, 11 | "prefix": "" 12 | }, 13 | "aliases": { 14 | "components": "@/components", 15 | "utils": "@/lib/utils", 16 | "ui": "@/components/ui", 17 | "lib": "@/lib", 18 | "hooks": "@/hooks" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /supabase/migrations/20250101000001_add_is_done_to_tasks.sql: -------------------------------------------------------------------------------- 1 | /* 2 | # Add isDone field to tasks table 3 | 4 | This migration adds an isDone boolean field to the tasks table 5 | to allow users to mark tasks as completed without moving them 6 | between columns. 7 | */ 8 | 9 | -- Add isDone column to tasks table 10 | ALTER TABLE public.tasks 11 | ADD COLUMN is_done BOOLEAN DEFAULT FALSE; 12 | 13 | -- Create index for better query performance 14 | CREATE INDEX idx_tasks_is_done ON public.tasks(is_done); 15 | 16 | -- Add comment for documentation 17 | COMMENT ON COLUMN public.tasks.is_done IS 'Whether the task is marked as done/completed'; -------------------------------------------------------------------------------- /hooks/use-mobile.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react" 2 | 3 | const MOBILE_BREAKPOINT = 768 4 | 5 | export function useIsMobile() { 6 | const [isMobile, setIsMobile] = React.useState(undefined) 7 | 8 | React.useEffect(() => { 9 | const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`) 10 | const onChange = () => { 11 | setIsMobile(window.innerWidth < MOBILE_BREAKPOINT) 12 | } 13 | mql.addEventListener("change", onChange) 14 | setIsMobile(window.innerWidth < MOBILE_BREAKPOINT) 15 | return () => mql.removeEventListener("change", onChange) 16 | }, []) 17 | 18 | return !!isMobile 19 | } 20 | -------------------------------------------------------------------------------- /hooks/use-mouse.ts: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import { useEffect, useState } from "react"; 4 | 5 | export const useMouse = () => { 6 | const [mousePosition, setMousePosition] = useState<{ 7 | x: number | null; 8 | y: number | null; 9 | }>({ x: null, y: null }); 10 | 11 | useEffect(() => { 12 | const updateMousePosition = (ev: MouseEvent) => { 13 | setMousePosition({ x: ev.clientX, y: ev.clientY }); 14 | }; 15 | window.addEventListener("mousemove", updateMousePosition); 16 | return () => { 17 | window.removeEventListener("mousemove", updateMousePosition); 18 | }; 19 | }, []); 20 | 21 | return mousePosition; 22 | }; -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # next.js 12 | /.next/ 13 | /out/ 14 | 15 | # production 16 | /build 17 | 18 | # misc 19 | .DS_Store 20 | *.pem 21 | 22 | # debug 23 | npm-debug.log* 24 | yarn-debug.log* 25 | yarn-error.log* 26 | 27 | # local env files 28 | .env 29 | .env*.local 30 | 31 | # vercel 32 | .vercel 33 | 34 | # typescript 35 | *.tsbuildinfo 36 | next-env.d.ts 37 | 38 | # prisma 39 | /prisma/generated 40 | 41 | # IDE and editor files 42 | .cursor/ 43 | .vscode/ 44 | .idea/ 45 | *.swp 46 | *.swo 47 | -------------------------------------------------------------------------------- /lib/stripe.ts: -------------------------------------------------------------------------------- 1 | import Stripe from 'stripe'; 2 | 3 | export const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!, { 4 | apiVersion: '2023-10-16', 5 | typescript: true, 6 | }); 7 | 8 | export const getURL = () => { 9 | let url = 10 | process?.env?.NEXT_PUBLIC_SITE_URL ?? // Set this to your site URL in production env. 11 | process?.env?.NEXT_PUBLIC_VERCEL_URL ?? // Automatically set by Vercel. 12 | 'http://localhost:3000/'; 13 | // Make sure to include `https://` when not localhost. 14 | url = url.includes('http') ? url : `https://${url}`; 15 | // Make sure to include a trailing `/`. 16 | url = url.charAt(url.length - 1) === '/' ? url : `${url}/`; 17 | return url; 18 | }; -------------------------------------------------------------------------------- /supabase/migrations/20250621183000_add_slug_to_projects.sql: -------------------------------------------------------------------------------- 1 | -- Add slug column to projects table 2 | ALTER TABLE projects ADD COLUMN slug TEXT; 3 | 4 | -- Create unique index on slug to ensure uniqueness 5 | CREATE UNIQUE INDEX projects_slug_idx ON projects(slug); 6 | 7 | -- Update existing projects to have a slug based on their name 8 | UPDATE projects 9 | SET slug = LOWER( 10 | REGEXP_REPLACE( 11 | REGEXP_REPLACE( 12 | REGEXP_REPLACE(name, '[^a-zA-Z0-9\s-]', '', 'g'), 13 | '\s+', '-', 'g' 14 | ), 15 | '-+', '-', 'g' 16 | ) 17 | ) || '-' || SUBSTRING(id::text, 1, 8); 18 | 19 | -- Make slug column NOT NULL after populating existing records 20 | ALTER TABLE projects ALTER COLUMN slug SET NOT NULL; -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": ["dom", "dom.iterable", "esnext"], 5 | "allowJs": true, 6 | "skipLibCheck": true, 7 | "strict": true, 8 | "noEmit": true, 9 | "esModuleInterop": true, 10 | "module": "esnext", 11 | "moduleResolution": "bundler", 12 | "resolveJsonModule": true, 13 | "isolatedModules": true, 14 | "jsx": "preserve", 15 | "incremental": true, 16 | "plugins": [ 17 | { 18 | "name": "next" 19 | } 20 | ], 21 | "paths": { 22 | "@/*": ["./*"] 23 | } 24 | }, 25 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], 26 | "exclude": ["node_modules"] 27 | } 28 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | # ---- Dependencies ---- 2 | FROM node:20-alpine AS deps 3 | WORKDIR /app 4 | COPY package.json package-lock.json ./ 5 | RUN npm ci --prefer-offline --no-audit 6 | 7 | # ---- Builder ---- 8 | FROM node:20-alpine AS builder 9 | WORKDIR /app 10 | COPY --from=deps /app/node_modules ./node_modules 11 | COPY . . 12 | ENV NEXT_TELEMETRY_DISABLED 1 13 | RUN npm run build 14 | 15 | # ---- Production ---- 16 | FROM node:20-alpine AS runner 17 | WORKDIR /app 18 | ENV NODE_ENV production 19 | ENV NEXT_TELEMETRY_DISABLED 1 20 | COPY --from=builder /app/public ./public 21 | COPY --from=builder /app/.next ./.next 22 | COPY --from=builder /app/node_modules ./node_modules 23 | COPY --from=builder /app/package.json ./package.json 24 | EXPOSE 3000 25 | CMD ["npm", "start"] -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | ## Supported Versions 4 | 5 | Currently supported, maintained and updated versions: 6 | 7 | | Version | Supported | 8 | | ------- | ------------------ | 9 | | 1.x | :white_check_mark: | 10 | 11 | 12 | ## Security Updates 13 | 14 | We take security seriously. Security updates are released as soon as possible after a vulnerability is discovered and verified. 15 | 16 | ## Reporting a Vulnerability 17 | 18 | If you discover a security vulnerability, please follow these steps: 19 | 20 | 1. **DO NOT** disclose the vulnerability publicly. 21 | 2. Send a detailed report to: `ua@kanba.co`. 22 | 3. Include in your report: 23 | - A description of the vulnerability 24 | - Steps to reproduce the issue 25 | - Potential impact 26 | -------------------------------------------------------------------------------- /components/ui/label.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import * as React from "react" 4 | import * as LabelPrimitive from "@radix-ui/react-label" 5 | import { cva, type VariantProps } from "class-variance-authority" 6 | 7 | import { cn } from "@/lib/utils" 8 | 9 | const labelVariants = cva( 10 | "text-xs font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70" 11 | ) 12 | 13 | const Label = React.forwardRef< 14 | React.ElementRef, 15 | React.ComponentPropsWithoutRef & 16 | VariantProps 17 | >(({ className, ...props }, ref) => ( 18 | 23 | )) 24 | Label.displayName = LabelPrimitive.Root.displayName 25 | 26 | export { Label } 27 | -------------------------------------------------------------------------------- /components/ui/input.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react" 2 | 3 | import { cn } from "@/lib/utils" 4 | 5 | const Input = React.forwardRef>( 6 | ({ className, type, ...props }, ref) => { 7 | return ( 8 | 17 | ) 18 | } 19 | ) 20 | Input.displayName = "Input" 21 | 22 | export { Input } 23 | -------------------------------------------------------------------------------- /components/ui/textarea.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | 3 | import { cn } from '@/lib/utils'; 4 | 5 | export interface TextareaProps 6 | extends React.TextareaHTMLAttributes {} 7 | 8 | const Textarea = React.forwardRef( 9 | ({ className, ...props }, ref) => { 10 | return ( 11 |