Modern Kanban ToDo app built with SvelteKit, Hasura GraphQL, and PostgreSQL.
nvm)Node & Dependencies
# Optional: Use same Node version across devices
nvm install && nvm use
# Install dependencies
npm ci
# Windows troubleshooting (if needed)
npm install --maxsockets=1
Environment Setup
# Copy and configure environment files
cp .env.example .env
cp hasura/.env.example hasura/.env
cp .env.test.example .env.test
# Edit .env files with your database credentials
Backend Setup
# Start Hasura
cd hasura
docker-compose up -d
# Configure Hasura
cp config.example.yaml config.yaml
# Edit config.yaml with your admin password
# Apply migrations and metadata
hasura migrate apply --all-databases
hasura metadata apply
# Optional: Load seed data (creates [email protected] user)
hasura seed apply
# Open Hasura Console
hasura console
# Console opens at http://localhost:9695
Verify Installation
npm run check
npm test
Start Development
npm run dev
# Opens at http://localhost:5173
MCP (Model Context Protocol) servers enhance Claude Code with browser automation, database access, and advanced problem-solving capabilities.
Required MCP Servers:
# 1. Playwright - Browser testing & console logs
claude mcp add playwright -- npx @playwright/mcp@latest
# 2. Sequential Thinking - Complex problem solving
claude mcp add sequential-thinking -- npx -y @modelcontextprotocol/server-sequential-thinking
# 3. Filesystem - Direct file operations (RECOMMENDED)
# Windows:
claude mcp add filesystem -- npx -y @modelcontextprotocol/server-filesystem C:/git/svelte-todo-kanban
# macOS/Linux:
claude mcp add filesystem -- npx -y @modelcontextprotocol/server-filesystem /path/to/svelte-todo-kanban
Optional MCP Servers:
# Context7 - Latest framework documentation
claude mcp add --transport http context7 https://mcp.context7.com/mcp/
# GitHub - Version control operations
claude mcp add --transport http github https://api.githubcopilot.com/mcp/
claude mcp list
# Should show (✓ Connected):
# - playwright
# - sequential-thinking
# - filesystem
# - context7 (if installed)
Once configured, MCP servers are automatically available in all Claude Code sessions:
Example workflow:
# In Claude Code, you can now say:
"Use Playwright to test the drag-and-drop at localhost:5173"
"Use sequential thinking to plan the real-time collaboration feature"
"Use filesystem to rename all .svelte files to use new naming convention"
Frontend: Svelte 5, SvelteKit, TypeScript, Tailwind CSS, shadcn-svelte
Backend: Hasura GraphQL, PostgreSQL
Auth: Auth.js with JWT tokens
Rich Text: svelte-tiptap (Markdown support planned)
Testing: Playwright (E2E), Vitest (unit/component)
i18n: sveltekit-i18n
src/
├── routes/
│ ├── [lang]/ # Language-based routing
│ └── api/ # Auth & file uploads
├── lib/
│ ├── components/
│ │ ├── todo/ # Todo components
│ │ ├── listBoard/ # Board/list components
│ │ └── ui/ # Shared UI (shadcn)
│ ├── stores/ # State management
│ ├── graphql/
│ │ ├── client.ts # GraphQL client
│ │ ├── documents.ts # All queries/mutations
│ │ └── generated.ts # Auto-generated types
│ └── locales/ # i18n translations
hasura/
├── metadata/ # GraphQL schema, permissions
├── migrations/ # Database migrations
└── seeds/ # Test data
tests/
└── e2e/ # Playwright tests
Stores follow a factory pattern in src/lib/stores/*.svelte.ts:
function createStore() {
const state = $state({
items: [],
loading: false,
error: null
});
async function loadItems() {
if (!browser) return; // Always check browser
state.loading = true;
try {
const data = await request(GET_ITEMS, {});
state.items = data.items || [];
} catch (error) {
state.error = error.message;
} finally {
state.loading = false;
}
}
return {
get items() { return state.items; },
get loading() { return state.loading; },
loadItems
};
}
export const store = createStore();
Key Rules:
$state object for all reactive stateif (!browser) before browser APIsfinally for loading state{ success, message, data? } from mutationssrc/lib/graphql/documents.tsnpm run generate to generate typessrc/lib/graphql/generated.tsrequest() from src/lib/graphql/client.tsimport { request } from '$lib/graphql/client';
import { GET_BOARDS } from '$lib/graphql/documents';
import type { GetBoardsQuery } from '$lib/graphql/generated';
const data: GetBoardsQuery = await request(GET_BOARDS, { user_id });
# Open Hasura Console
cd hasura
hasura console
# Console features:
# - Data tab: Browse tables, run SQL
# - API tab: Test GraphQL queries
# - Events tab: Check triggers
import { loggingStore } from '$lib/stores/logging.svelte';
// Production logs (auto-saved to DB)
loggingStore.error('Component', 'Error msg', { error });
loggingStore.warn('Component', 'Warning', { context });
loggingStore.info('Component', 'Info', { data });
// Dev only (not persisted)
loggingStore.debug('Component', 'Debug', { data });
View logs at: /[lang]/logs
# Development
npm run dev # Start dev server
npm run check # Type checking
npm test # Run tests
npm run generate # Generate GraphQL types
# Backend (from hasura/ directory)
hasura console # Open Hasura Console
hasura metadata apply # Apply metadata changes
hasura migrate apply --all-databases
hasura migrate create "migration_name" --from-server
# MCP
claude mcp list # List configured servers
claude mcp add # Add new server
claude mcp remove # Remove server
# Clean install
npm run cu # Unix-like systems
npm run cw # Windows
When NODE_ENV=development:
[email protected]/auth/signin# All tests
npm test
# E2E only
npm run test:e2e
# Unit/Component only
npm run test:unit
# With UI
npm run test:e2e -- --ui
SEO-friendly URLs with auto-generated aliases:
/[lang]/[username]/[boardAlias]/[lang]/[username]/[boardAlias]/[todoAlias]Examples:
/en/john-w/work-projects/en/sarah/personal-tasks/shoppingAliases are auto-generated by PostgreSQL functions:
my-board, my-board-2)Planned: Custom usernames, shareable URLs without /[lang]
board_invitations row (status='pending')board_members row, updates statusnpm run build
npm run preview
npx shadcn-svelte add <component>)npm run check # Must pass
npm test # Must pass
Use MCP tools for verification:
Follow store patterns:
$stateWrite tests:
Document changes:
todo/ folderIf you encounter dependency conflicts:
npm install --maxsockets=1
Check .env and hasura/.env files have correct credentials.
# Check status
claude mcp list
# Reconnect
claude mcp remove <server-name>
claude mcp add <server-name> -- <command>
[Your License Here]
For issues or questions, please open an issue on GitHub.