A gamified self-development platform inspired by Solo Leveling. This is the first vertical slice: user authentication, goal creation, and a Quest Board UI backed by Supabase with Row Level Security.
solo_leveling/
βββ apps/
β βββ api/ # NestJS API server
β β βββ src/
β β β βββ goals/ # Goals CRUD endpoints
β β β βββ health/ # Health check endpoints
β β β βββ supabase/ # Auth guard & Supabase client
β β β βββ app.module.ts
β β β βββ main.ts
β β βββ package.json
β β
β βββ web/ # Next.js 14 (App Router)
β βββ src/
β β βββ app/ # Pages (auth, dashboard)
β β βββ components/ # System UI components
β β βββ lib/ # Auth context, API client
β βββ package.json
β
βββ packages/
β βββ shared/ # Shared TypeScript types
β βββ src/index.ts # Goal, Quest enums, DTOs
β
βββ infra/
β βββ supabase/
β βββ migrations/ # SQL migrations with RLS
β βββ config.toml # Supabase local config
β
βββ package.json # Monorepo root
- Node.js >= 18
- pnpm >= 8
- Docker Desktop (for Supabase local) - REQUIRED
- Supabase CLI - See installation instructions below
# Install pnpm if you don't have it
npm install -g pnpm
# Install all workspace dependencies
pnpm installWindows (Using Scoop):
# Install Scoop if needed
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser
Invoke-RestMethod -Uri https://get.scoop.sh | Invoke-Expression
# Install Supabase
scoop bucket add supabase https://github.com/supabase/scoop-bucket.git
scoop install supabaseOr download manually: https://github.com/supabase/cli/releases
# Make sure Docker Desktop is running first!
# Initialize and start Supabase
pnpm supabase:start
# OR
cd infra/supabase
supabase startβ±οΈ First time takes 5-10 minutes - downloads Docker images
Important: Copy the output values:
API URL(typically http://localhost:54321)anon keyservice_role key
For API (apps/api/.env):
cp apps/api/.env.example apps/api/.envEdit apps/api/.env:
SUPABASE_URL=http://localhost:54321
SUPABASE_ANON_KEY=<your_anon_key>
SUPABASE_SERVICE_ROLE_KEY=<your_service_role_key>
PORT=3001
NODE_ENV=developmentFor Web (apps/web/.env.local):
cp apps/web/.env.example apps/web/.env.localEdit apps/web/.env.local:
NEXT_PUBLIC_SUPABASE_URL=http://localhost:54321
NEXT_PUBLIC_SUPABASE_ANON_KEY=<your_anon_key>
NEXT_PUBLIC_API_URL=http://localhost:3001/apipnpm supabase:migrateThis creates the goals table and enables RLS policies.
pnpm shared:buildOption 1: Start all services together
pnpm devOption 2: Start individually
# Terminal 1: API
pnpm api:dev
# Terminal 2: Web
pnpm web:dev- Web App: http://localhost:3000
- API: http://localhost:3001/api
- Supabase Studio: http://localhost:54323
- Navigate to http://localhost:3000
- Click "Begin Journey" β Sign Up
- Create account with email/password
- You'll be redirected to the Dashboard
- Click "+ New Quest"
- Enter a goal title and click "Create Quest"
- Your goal appears in the Quest Board!
curl http://localhost:3001/api/health/simpleExpected response:
{
"ok": true,
"timestamp": "2026-01-07T...",
"service": "Solo Leveling API"
}- User signs in via Next.js β Supabase Auth issues JWT
- Next.js client stores JWT automatically (in cookies/localStorage)
- API requests include JWT in
Authorization: Bearer <token>header - NestJS AuthGuard validates JWT using Supabase client:
const { data: { user } } = await supabase.auth.getUser(token);
- Supabase validates:
- JWT signature (using secret key)
- Token expiration
- Token structure
- User ID extracted from validated JWT
- RLS policies use
auth.uid()which matches the user ID from JWT
The database has these policies on the goals table:
-- Users can only SELECT their own goals
CREATE POLICY "Users can read own goals"
ON goals FOR SELECT
TO authenticated
USING (auth.uid() = user_id);
-- Users can only INSERT with their own user_id
CREATE POLICY "Users can insert own goals"
ON goals FOR INSERT
TO authenticated
WITH CHECK (auth.uid() = user_id);Server-side security:
- API explicitly sets
user_idfrom authenticated token - Client cannot override
user_idin requests - Even if client tries to manipulate data, RLS policies block it
- Sign up with User A
- Create 2-3 goals as User A
- Verify goals appear in dashboard
- Delete one goal
- Sign out
- Sign up with User B (different email)
- Verify User B sees NO goals initially
- Create 1 goal as User B
- Verify User B sees only their 1 goal
- Sign out
- Sign in as User A again
- Verify User A still sees their original goals (NOT User B's)
- This confirms RLS is working!
Open Supabase Studio (http://localhost:54323):
- Go to SQL Editor
- Run query:
SELECT id, user_id, title, created_at FROM goals;
- You should see ALL goals from ALL users
- Note the different
user_idvalues
Now test RLS is active:
-- This should return only YOUR goals when run from client
SELECT * FROM goals WHERE user_id = auth.uid();Try to manipulate requests (requires tools like Postman):
- Sign in as User A, get token from browser DevTools
- Try to create a goal with User B's
user_id:curl -X POST http://localhost:3001/api/v1/goals \ -H "Authorization: Bearer <user_a_token>" \ -H "Content-Type: application/json" \ -d '{"title": "Hack attempt", "user_id": "<user_b_id>"}'
- Expected: Server ignores client's
user_idand uses authenticated user's ID - Result: Goal is created for User A, not User B (RLS protection working!)
curl http://localhost:3001/api/v1/goalsExpected: 401 Unauthorized error
CREATE TABLE goals (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID NOT NULL REFERENCES auth.users(id) ON DELETE CASCADE,
title TEXT NOT NULL,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
-- Index for RLS performance
CREATE INDEX idx_goals_user_id ON goals(user_id);
-- RLS enabled
ALTER TABLE goals ENABLE ROW LEVEL SECURITY;GET /api/health- Terminus health checkGET /api/health/simple- Simple OK response
GET /api/v1/goals- List user's goalsPOST /api/v1/goals- Create goal{ "title": "Complete 100 push-ups daily", "description": "Optional description", "difficulty": "C_RANK" }GET /api/v1/goals/:id- Get specific goalDELETE /api/v1/goals/:id- Delete goal
Reusable panel component with signature Solo Leveling look:
<SystemWindow title="STATUS WINDOW">
{/* content */}
</SystemWindow>Individual quest/goal display with delete functionality:
<QuestCard
title="My Goal"
description="Description"
createdAt="2026-01-07"
onDelete={() => handleDelete()}
/>Displays stats with progress bars:
<StatusBar label="Level" value={5} maxValue={10} color="gold" /># Development
pnpm dev # Start all services
pnpm api:dev # Start API only
pnpm web:dev # Start web only
# Build
pnpm build # Build all packages
pnpm shared:build # Build shared package
# Supabase
pnpm supabase:start # Start local Supabase
pnpm supabase:stop # Stop local Supabase
pnpm supabase:status # Check Supabase status
pnpm supabase:migrate # Run/reset migrationsCause: Supabase database is not running.
Solution:
- Make sure Docker Desktop is running (green icon)
- Start Supabase:
cd infra/supabase && supabase start - Verify:
supabase status(should show all services running) - Restart API and Web servers
π See FIX_NOW.md for detailed step-by-step instructions
Solution: Install Supabase CLI:
- Windows: Use Scoop (see Prerequisites section)
- Manual: Download from https://github.com/supabase/cli/releases
Solution:
- Open Docker Desktop application
- Wait for it to fully start (green icon in system tray)
- Try
supabase startagain
pnpm shared:build- Verify
.envfiles are created (not just.env.example) - Verify you copied the keys from
pnpm supabase:startoutput
# Check what's using the port
netstat -ano | findstr :3000 # Windows
lsof -i :3000 # Mac/Linux
# Or use different ports in .env files- Ensure Docker Desktop is running
- Try:
pnpm supabase:stopthenpnpm supabase:start
- Check browser console for errors
- Verify API is running on port 3001
- Check
NEXT_PUBLIC_API_URLin.env.local
This vertical slice demonstrates:
- β Authentication with Supabase
- β Row Level Security working correctly
- β API with health check + CRUD
- β Next.js UI with Solo Leveling theme
- β Monorepo structure with shared types
Future enhancements (not in this slice):
- Health Connect integration for fitness tracking
- Penalties/rewards system
- Quest difficulty and XP
- Level progression
- Daily quests
- Achievement system
- Using pnpm workspaces for monorepo management
- NestJS with Terminus for health checks
- Next.js 14 App Router with client components
- Supabase Auth with JWT validation
- Tailwind with custom Solo Leveling theme
- TypeScript throughout
Built with βοΈ by a Hunter seeking to level up