# BaseDeck User Guide — How the App Works

> Everything a developer needs to know about using BaseDeck: installation, sign-in, all features, security, troubleshooting, and how to report issues.

**App:** https://basedeck.netlify.app/dashboard  
**Docs:** https://basedeck.netlify.app/docs.html  
**Guides:** https://basedeck.netlify.app/guides.html  

---

## Table of contents

1. [Installing BaseDeck](#1-installing-basedeck)
2. [Signing in — Personal Access Token](#2-signing-in)
3. [Project selection](#3-project-selection)
4. [PIN lock](#4-pin-lock)
5. [Edge Functions tab](#5-edge-functions-tab)
6. [Database tab](#6-database-tab)
7. [SQL tab](#7-sql-tab)
8. [Overview tab](#8-overview-tab)
9. [Settings tab](#9-settings-tab)
10. [Security model](#10-security-model)
11. [Offline behaviour](#11-offline-behaviour)
12. [Troubleshooting](#12-troubleshooting)
13. [Reporting issues](#13-reporting-issues)

---

## 1. Installing BaseDeck

BaseDeck is a PWA — no app store needed. Install it directly from your browser.

**Android (Chrome):**
1. Open https://basedeck.netlify.app in Chrome
2. Tap the three-dot menu (top right)
3. Tap **Add to Home Screen**
4. Confirm — the BaseDeck icon appears on your home screen
5. Open from the home screen — it launches full-screen like a native app

**iOS (Safari):**
1. Open https://basedeck.netlify.app in **Safari** (not Chrome — Apple restricts PWA installation to Safari on iOS)
2. Tap the Share button (rectangle with upward arrow)
3. Scroll down and tap **Add to Home Screen**
4. Confirm

**Using it in-browser without installing:**  
You can use BaseDeck directly at https://basedeck.netlify.app/dashboard without installing. Installation is optional but recommended — the installed version loads faster, can work offline, and feels like a native app.

---

## 2. Signing In

BaseDeck uses your Supabase **Personal Access Token (PAT)** to authenticate.

### What is a Personal Access Token?

A PAT is a long-lived credential that gives programmatic access to the Supabase Management API. It is the same token the Supabase CLI uses when you run `supabase login`. It grants access to your entire Supabase account — all projects, all functions, all data.

### How to generate a PAT

1. Go to https://supabase.com and log in
2. Click your avatar (top right) → **Account**
3. Click **Access Tokens** in the sidebar
4. Click **Generate new token**
5. Give it a name (e.g. "BaseDeck") and copy the token — it will only be shown once

### Pasting the token into BaseDeck

Paste the token into the password field on the BaseDeck login screen and tap **Connect**. The token is sent immediately to the BaseDeck server for encryption — it is never stored raw on your device.

### What if I lose my token?

Generate a new one from the Supabase dashboard and log into BaseDeck again. Old tokens can be revoked from the same Access Tokens page.

---

## 3. Project Selection

After signing in, BaseDeck fetches the list of Supabase projects on your account and shows them as cards. Tap the project you want to work with.

You can switch projects at any time from the **Settings** tab without logging out. Switching projects does not require re-entering your token.

---

## 4. PIN Lock

BaseDeck requires a 4-digit PIN on every cold start before any data is accessible.

### Setting your PIN

On first launch after sign-in, BaseDeck prompts you to set a PIN. Choose a 4-digit code you will remember.

### Changing your PIN

Go to **Settings → Change PIN**. You will need to enter your current PIN first, then set the new one.

### Lockout

After 5 consecutive wrong PIN attempts, BaseDeck wipes the stored encrypted token from your device and returns to the login screen. This protects against brute-force access on a lost or stolen phone. You will need to sign in again with your Personal Access Token.

### Why does BaseDeck need a PIN if my phone already has a lock screen?

The PIN is a second layer of protection specifically for BaseDeck's data. If someone gains access to your unlocked phone, or if the screen lock is bypassed, the PIN ensures BaseDeck's content and your Supabase credentials remain protected.

---

## 5. Edge Functions Tab

The Functions tab is BaseDeck's core feature — it is why the app exists.

### Viewing deployed functions

The Functions tab lists all Edge Functions currently deployed in your selected Supabase project. Each card shows the function name and its status.

### Deploying a single-file function

1. Tap **New Function** (or the deploy button)
2. Enter a function name (lowercase, hyphens allowed — e.g. `send-email`)
3. Write or paste your Deno/TypeScript function body in the CodeMirror editor
4. Choose whether to require a JWT (toggle the JWT verification switch)
5. Tap **Deploy**
6. Watch the deploy log stream in real time

The function must be a valid Deno module with a default export that handles a `Request` and returns a `Response`. Example:

```typescript
Deno.serve(async (req) => {
  return new Response(JSON.stringify({ ok: true }), {
    headers: { "Content-Type": "application/json" },
  });
});
```

### Deploying a multi-file function

Use multi-file mode when your function imports utilities from other files.

1. Switch to **Multi-file** mode using the toggle at the top of the editor
2. Your first file is the entry point — give it the function name
3. Tap **Add file** for each additional module
4. Name each file with the path your entry point uses to import it (e.g. `utils/email.ts`)
5. Write the code for each file
6. Tap **Deploy** — BaseDeck bundles all files and resolves import paths automatically

### The deploy log

Every deploy streams a timestamped log panel showing server-side output line by line. Green lines are progress steps; red lines indicate errors. If a deploy fails, the full error message from the Supabase bundle endpoint appears here.

Common deploy errors:
- **Syntax error in your TypeScript** — check the error line number in the log and fix the code
- **Invalid function name** — names must be lowercase letters, numbers, or hyphens; no spaces or underscores
- **Import path not found** — in multi-file mode, the import path in your code must exactly match the filename you added

### Invoking a function

Tap any deployed function from the list to open its detail view. From here you can:

- Set the HTTP method (GET, POST, PUT, PATCH, DELETE)
- Write a request body (JSON or plain text)
- Add custom headers as key-value pairs (one per line: `Key: Value`)
- Tap **Send** and inspect the full response — status code, response body, and round-trip time in milliseconds

---

## 6. Database Tab

The Database tab lets you browse your project's live data without writing SQL.

### Browsing tables

All tables in your project's `public` schema are listed on load. Tap a table name to open it.

### Row pagination

Rows load 50 at a time. Use **Prev** and **Next** at the bottom to page through the data. The current page and approximate total are displayed above the table.

### Column display

All columns are shown. Long text values are truncated in the cell but fully visible by scrolling horizontally. `null` values are shown as a distinct `NULL` label.

### Limitations

The database browser is **read-only**. It does not support inserting, updating, or deleting rows. For data modifications, use the SQL Editor tab.

The browser only shows tables in the `public` schema. Views, functions, and other schema objects are not listed here but can be queried from the SQL tab.

---

## 7. SQL Tab

The SQL tab gives you a full Postgres query interface.

### Writing queries

The CodeMirror editor provides SQL syntax highlighting, bracket matching, and auto-close brackets. Write any valid Postgres SQL — SELECT, INSERT, UPDATE, DELETE, CREATE, and so on.

### Running queries

Tap **Run**. Results appear below the editor in a scrollable table showing column names and row data. The row count and execution time in milliseconds appear above the table.

Queries that return no rows (such as INSERT or UPDATE) show a success confirmation with the number of rows affected.

### Destructive query confirmation

Queries that contain `DROP`, `DELETE`, `TRUNCATE`, or `ALTER TABLE` trigger a confirmation dialog before execution. This is a safeguard against accidental data loss on a small touchscreen. Read the dialog carefully — these operations cannot be undone.

### Query history

BaseDeck stores your last 20 executed queries. Tap **History** in the SQL toolbar to browse them. Tap any entry to load it back into the editor.

### Snippets

Frequently used queries can be saved as named snippets.

1. Write the query in the editor
2. Tap **Save** and give it a name
3. The snippet is stored on your device and available under the **Snippets** button on every future visit

Snippets persist across sessions. They are stored in `localStorage` and are not tied to a specific project — if you switch projects, the same snippets are available.

---

## 8. Overview Tab

The Overview tab shows a summary of the currently selected project:

- Project name, ID, and region
- REST API URL
- Database status
- Project reference string (used in Supabase CLI and SDK configuration)

This tab is useful when you need to copy your project reference or API URL without navigating to the Supabase dashboard.

---

## 9. Settings Tab

The Settings tab contains project management and app configuration options.

### Copy API keys

Tap **Copy Anon Key** or **Copy Service Role Key** to copy the key to your clipboard instantly. Useful when you need to paste a key into a `.env` file or configuration.

### Switch project

Tap **Switch Project** to return to the project selector without logging out. Your token remains active — you just pick a different project.

### Sign out

Tap **Sign Out** to clear the encrypted token from your device and return to the login screen. The next session will require your Personal Access Token again.

### Change PIN

See [PIN Lock](#4-pin-lock) above.

### Developer console (Eruda)

BaseDeck ships with [Eruda](https://github.com/liriliri/eruda) — a mobile browser devtools panel. It is disabled by default. To enable it, tap **Open Console** in Settings. Eruda gives you a console, network inspector, and element inspector directly on your phone. Useful for debugging API responses or inspecting BaseDeck itself. Disable it by toggling it off in Settings or clearing `localStorage`.

---

## 10. Security Model

### Token encryption

Your Supabase Personal Access Token is encrypted with **AES-256-GCM** the moment you paste it. The encryption happens in a Netlify serverless function using a server-side `ENCRYPTION_KEY` environment variable. The raw token is never stored on your device, never returned to the browser after login, and never logged.

What is stored on your device: the AES-256-GCM **ciphertext** — useless without the server-side key.

### API proxying

Every call to the Supabase Management API and PostgREST goes through BaseDeck's Netlify Functions. The server decrypts the ciphertext on demand, makes the outbound request to Supabase, and returns the result. The raw token never passes through browser network requests after initial login.

This means: even if someone inspects your browser's network traffic, they will not see your raw Supabase PAT.

### PIN protection

The PIN lock is a client-side safeguard against physical access on an unlocked device. It is not a substitute for keeping your device secure. The 5-attempt lockout wipes the encrypted token from `localStorage` on the device — not from the Supabase account. Your token remains valid on Supabase; only the device copy is cleared.

### What BaseDeck does NOT have access to

BaseDeck never stores your token on any database or logging system. The server decrypts it ephemerally per request and discards the value immediately. BaseDeck also has no access to the data inside your Supabase database beyond what your requests ask for.

---

## 11. Offline Behaviour

BaseDeck's service worker caches the app shell (HTML, CSS, JS) and static assets. This means:

- The app **loads** when offline
- The PIN screen works offline
- The editor works offline — you can write code without a connection

However, all features that need to talk to Supabase (deploy, query, browse, invoke) require an internet connection. These will show an error message when offline.

---

## 12. Troubleshooting

### The app won't open / blank screen

1. Hard-refresh the page (pull down to refresh on mobile)
2. Clear the site data in your browser: Settings → Site settings → basedeck.netlify.app → Clear storage
3. Reinstall the PWA — remove the home screen icon and add it again
4. Check your internet connection

### I forgot my PIN

There is no PIN recovery mechanism. Tap **Forgot PIN** on the lock screen (if shown) — this clears your encrypted token and returns to login. You will need to enter your Personal Access Token again.

Alternatively, go to your browser's settings, find site data for basedeck.netlify.app, and clear it manually. This resets the app completely.

### "Invalid token" or "Unauthorised" error on login

- Make sure you are pasting a **Personal Access Token**, not your project's anon key or service role key — those are different credentials
- Personal Access Tokens start with `sbp_`
- The token may have been revoked — go to Supabase → Account → Access Tokens and check

### Functions are not listed / project list is empty

- Check your internet connection
- Your PAT may have expired or been revoked — sign out and sign in again with a fresh token
- Confirm the project exists and is active in your Supabase dashboard

### Deploy fails immediately with "400 Bad Request"

- Function name is invalid — must be lowercase, hyphens only, no underscores or spaces
- The function body has a TypeScript syntax error — check the deploy log for the exact error line

### Deploy log shows "bundle error" or "Deno compile error"

- A TypeScript syntax error in your code — read the error message in the log carefully
- In multi-file mode: an import path in your entry file doesn't match the filename you added — paths must match exactly, including subdirectory prefixes

### SQL query returns an error

- Check the query for syntax errors — the error message from Postgres is returned directly and will identify the issue
- If querying a table that doesn't exist in the `public` schema, reference it with the full schema prefix (e.g. `SELECT * FROM auth.users`)
- Service role permission is used for SQL — most operations are permitted, but some system tables may be restricted

### The database tab shows no tables

- Your project may have no tables in the `public` schema yet
- Check the Supabase dashboard to confirm your tables exist in `public` and not in a custom schema

### CodeMirror editor is slow or unresponsive on older phones

- Close other browser tabs to free up memory
- Use the Eruda console (Settings → Open Console) to check for JavaScript errors
- Try using BaseDeck in the browser tab instead of the installed PWA — some older Android WebViews have memory constraints

### The app worked before but stopped working after an update

BaseDeck's service worker caches the app. After an update, the old cache may need clearing:
1. Go to your phone's browser settings
2. Find site data for basedeck.netlify.app
3. Clear cache (not necessarily storage — just cache)
4. Reload the app

---

## 13. Reporting Issues

BaseDeck is actively maintained by Godlove Tikum. If you find a bug, hit an unexpected error, or have a feature request:

**Contact via the website form:**  
https://basedeck.netlify.app/#contact  
Fill in your name, email, and a description of the issue. Include the error message if one was shown.

**Contact directly:**  
Email: godlovetikum@gmail.com  
X (Twitter): https://x.com/godlovetikum — DMs are open

### What to include in a bug report

A useful bug report tells the maintainer exactly how to reproduce the problem. Include:

1. **What you were doing** — which tab, what action (e.g. "deploying a single-file function named `my-func`")
2. **What happened** — the exact error message or behaviour
3. **What you expected** — what should have happened
4. **Your device and browser** — e.g. "Samsung Galaxy S22, Chrome 120" or "iPhone 13, Safari"
5. **The deploy log output** — if the issue involves a function deploy, copy the full log text from the deploy log panel
6. **Console output** — if you have the Eruda console enabled (Settings → Open Console), copy any red error lines from the Console tab

The more specific the report, the faster the fix.

### Opening the Eruda console for debugging

1. Open BaseDeck and get to the Settings tab
2. Tap **Open Console**
3. A floating Eruda button appears — tap it to open the devtools panel
4. Go to the **Console** tab to see JavaScript errors
5. Go to the **Network** tab to see API request and response details
6. Reproduce the problem and note any errors or failed requests

This information is extremely useful for debugging and makes issue reports much more actionable.

---

## Related resources

- **BaseDeck documentation:** https://basedeck.netlify.app/docs.html
- **Step-by-step guides:** https://basedeck.netlify.app/guides.html
- **Changelog:** https://basedeck.netlify.app/changelog.html
- **Supabase Edge Functions docs:** https://supabase.com/docs/guides/functions
- **Supabase Management API:** https://supabase.com/docs/reference/api
- **Deno runtime docs** (for writing Edge Functions): https://docs.deno.com
- **CodeMirror docs:** https://codemirror.net
