DEV Community

Saif Jlassi
Saif Jlassi

Posted on

Lakron : A Minimal, Encrypted, Realtime Life Scheduler with Supabase

Lakron: A Minimal, Encrypted, Realtime Life Scheduler with Supabase

Lakron is a minimal, smart life scheduler that keeps your data private and in sync. Every task is encrypted before it leaves your browser, and realtime sync means your schedule is always up to date everywhere.

How Encryption Works

Every task you create is encrypted in the browser using a key derived from your password and a salt. Only you can decrypt your data—nobody else, not even the database admin.

// TaskProvider.tsx
const generateKey = useMemo(() => {
  if (!currentProfile?.password) return ''
  return CryptoJS.PBKDF2(currentProfile.password, ENCRYPTION_SALT, { keySize: 256 / 32 }).toString()
}, [currentProfile?.password])
Enter fullscreen mode Exit fullscreen mode

When saving or loading a task, the title and description are encrypted/decrypted with this key:

// supabase.ts
function encrypt(text, key) {
  return CryptoJS.AES.encrypt(text, key).toString()
}
function decrypt(cipher, key) {
  return CryptoJS.AES.decrypt(cipher, key).toString(CryptoJS.enc.Utf8)
}
Enter fullscreen mode Exit fullscreen mode

How to Clone and Run Lakron

  1. Clone the repo:
   git clone https://github.com/laakri/lakron.git
   cd lakron
Enter fullscreen mode Exit fullscreen mode
  1. Install dependencies:
   npm install
Enter fullscreen mode Exit fullscreen mode
  1. Create a .env file in the root with your Supabase project keys. Use your own values, never share your real keys publicly!
   VITE_ENCRYPTION_KEY=your-random-salt
   VITE_SUPABASE_URL=https://your-project.supabase.co
   VITE_SUPABASE_KEY=your-service-role-key
   VITE_SUPABASE_ANON_KEY=your-anon-key
Enter fullscreen mode Exit fullscreen mode
  1. Start the dev server:
   npm run dev
Enter fullscreen mode Exit fullscreen mode

Enable Realtime on the Tasks Table

Lakron uses Supabase Realtime to sync tasks instantly across devices.

To enable this, turn on Realtime for the tasks table in your Supabase dashboard:

  • Go to your Supabase project
  • Click on "Database" → "Replication"
  • Find the tasks table and enable Realtime

SQL to Create the Tables (All in One Block)

If you need to create the profiles and tasks tables from scratch, here’s the full SQL:

-- Create profiles table
CREATE TABLE IF NOT EXISTS profiles (
  id SERIAL PRIMARY KEY,
  name VARCHAR(100) UNIQUE NOT NULL,
  password VARCHAR(255) NOT NULL,
  created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);

-- Create tasks table
CREATE TABLE IF NOT EXISTS tasks (
  id UUID DEFAULT gen_random_uuid() PRIMARY KEY,
  title VARCHAR(255) NOT NULL,
  time VARCHAR(10) NOT NULL,
  date DATE NOT NULL,
  completed BOOLEAN DEFAULT FALSE,
  type VARCHAR(10) CHECK (type IN ('task', 'event')) DEFAULT 'task',
  description TEXT,
  profile_id INTEGER REFERENCES profiles(id) ON DELETE CASCADE,
  created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
  priority INTEGER NOT NULL DEFAULT 2,
  recurring BOOLEAN NOT NULL DEFAULT false,
  recurrence_rule TEXT,
  "completedDates" TEXT[]
);

-- Add constraint to ensure recurrence_rule values are valid
ALTER TABLE tasks
  ADD CONSTRAINT IF NOT EXISTS check_recurrence_rule
  CHECK (
    recurrence_rule IN ('daily', 'weekly', 'monthly', 'yearly', 'custom')
    OR recurrence_rule IS NULL
  );

-- Optional: Standardize existing recurrence_rule values (safe to run even if table is empty)
UPDATE tasks SET recurrence_rule = 'daily' WHERE recurrence_rule = 'daily';
UPDATE tasks SET recurrence_rule = 'weekly' WHERE recurrence_rule = 'weekly';
UPDATE tasks SET recurrence_rule = 'monthly' WHERE recurrence_rule = 'monthly';
UPDATE tasks SET recurrence_rule = 'yearly' WHERE recurrence_rule = 'yearly';
UPDATE tasks SET recurrence_rule = 'custom'
  WHERE recurrence_rule IS NOT NULL
    AND recurrence_rule NOT IN ('daily', 'weekly', 'monthly', 'yearly');
Enter fullscreen mode Exit fullscreen mode

Realtime Sync

Supabase’s realtime channels keep tasks in sync across tabs and devices. The provider subscribes to changes for the current profile, so if you add or complete a task on your phone, it updates instantly on your laptop.

// TaskProvider.tsx
const unsubscribe = dbOperations.subscribeToTasks(currentProfile.id, (payload) => {
  // handle INSERT, UPDATE, DELETE
})
Enter fullscreen mode Exit fullscreen mode

Deployment

Deploying Lakron is as smooth as using it. The whole process is automated with GitHub Actions, so every push to the main branch triggers a build and deploy.

The workflow does three things:

  1. Installs dependencies and builds the frontend
  2. Copies the built static files to the server using SCP over SSH
  3. Reloads the Caddy server so your changes go live instantly

Here’s the gist of the deployment workflow:

# .github/workflows/deploy.yml
- name: Install dependencies and build
  run: |
    npm ci
    npm run build

- name: Deploy dist to server
  uses: appleboy/[email protected]
  with:
    host: ${{ secrets.SERVER_HOST }}
    username: ${{ secrets.SERVER_USER }}
    key: ${{ secrets.SERVER_SSH_KEY }}
    source: "dist/*"
    target: "/home/youruser/lakron/dist"

- name: Reload Caddy
  uses: appleboy/[email protected]
  with:
    host: ${{ secrets.SERVER_HOST }}
    username: ${{ secrets.SERVER_USER }}
    key: ${{ secrets.SERVER_SSH_KEY }}
    script: |
      sudo systemctl reload caddy
Enter fullscreen mode Exit fullscreen mode

You just need to add your server’s SSH key and connection info as GitHub secrets.

Caddy serves the static files from the dist directory, so as soon as the workflow finishes, your latest version is live.

No manual uploads, no downtime, just push and your encrypted, realtime scheduler is up to date for everyone.


Clone, set your env, run the SQL, enable realtime, and you’ve got a fully encrypted, realtime, minimal life scheduler.

Top comments (0)