Skip to content

Todo App

Build a collaborative todo application — authentication, per-user data isolation via RLS, real-time sync, and drag-and-drop reordering — using Pulsabase.

Mobile (React Native)

Native todo app with React Native + Pulsabase SDK. View on GitHub →

Authentication, database models with RLS owner policies, real-time table subscriptions, and drag-and-drop sort order — wired together with 12 SDK calls.

AreaCallsWhat it does
Auth3Sign up, sign in, get current user
Database7Create, read, update, delete, and reorder todos
Real-Time2Subscribe to INSERT / UPDATE / DELETE events
Total~12A collaborative, real-time todo app
Terminal window
git clone https://github.com/pulsabase/demo-todo-web
cd demo-todo-web
npm install
pulsabase login
pulsabase init # links to your Dashboard project
pulsabase db:sync # creates table, constraints, RLS policies
# Edit src/config.ts with your anon_key
npm run dev
models/Todo.ts
import { primary, text, boolean, integer, foreignId, ModelSchema } from 'pulsabase';
export default class Todo {
@primary
id: string;
@text(false)
title: string;
@boolean(false)
completed: boolean;
@foreignId({ references: 'id', on: 'users', onDelete: 'CASCADE' })
user_id: string;
@integer({ default: 0 })
sort_order: number;
static schema: ModelSchema = {
tableName: 'todos',
publication: true,
timestamps: true,
policies: [
// Each user can only read, update, or delete their own todos
{ action: ['SELECT', 'UPDATE', 'DELETE'], role: 'authenticated', owner: 'user_id' },
{ action: ['INSERT'], role: 'authenticated' },
],
};
}
import pb from './pulsabase';
import Todo from './models/Todo';
// RLS automatically filters to the current user's todos — no manual filtering needed
const todos = await pb.from(Todo)
.orderBy('sort_order', 'asc')
.find();
// Add a new todo
await pb.from(Todo).insert({
title: 'Buy groceries',
completed: false,
user_id: pb.auth.getUser()?.id,
});
// Real-time sync — changes from any device or session are pushed immediately
pb.from(Todo).on('INSERT', 'UPDATE', 'DELETE').listen(() => {
refreshTodos();
});