Documentation

How Sheetzo works.

Sheetzo is a real relational database wearing a spreadsheet, plus every surface your team actually uses on top of it. Two parts: the data layer, and the product surfaces built on it.

Start here

Sheetzo 101 - Getting started

New to Sheetzo? Read this first. The shortest path from sign-up to a working workspace, plus the five concepts every other page assumes you know.

01

What Sheetzo is

A relational database that looks and feels like a spreadsheet, with views, forms, dashboards, and an AI assistant on top.

Spreadsheet on the outside
Rows, columns, inline editing, keyboard navigation. If you have ever used a sheet, you already know how to move around.
Database on the inside
Typed fields, relations between tables, formulas, rollups, row-level permissions, and version history. Built for teams, not just one person.
Surfaces, not just storage
Same data renders as a Grid, Kanban, Calendar, Dashboard, public Form, or printable Report. Pick the surface for the job.
02

Core concepts in 60 seconds

The five words you need to read the rest of these docs.

Workspace
A container for everything your team works on: tables, views, dashboards, forms, members, and permissions.
Table
A typed collection of records. Customers, Orders, Tasks, Invoices. Every table has one primary field used as the record's label.
Field
A column with a type: text, number, date, single_select, file, relation, formula, rollup, and more. Type drives validation and rendering.
Record
A row in a table. Gets an immutable rec_xxxxxxxx ID and tracks created / updated timestamps automatically.
View
A saved configuration on top of a table: filters, sort, hidden columns, group-by, and surface (Grid / Kanban / Calendar / Dashboard).
03

Your first five minutes

The shortest path from sign-up to a workspace your team can actually use.

1. Create a workspace
From Home, click 'New workspace'. Give it a name and an emoji. Empty workspaces start clean; you add tables when you are ready.
2. Add a table
Use 'Add table' to create one from scratch, or pick a starter (CRM, Tasks, Orders). Starters ship with sensible fields and a default view.
3. Add a few records
Type into the grid like a spreadsheet, paste from a CSV, or use 'Import' to bring in a file. The column mapping dialog handles messy headers.
4. Save a view
Filter, sort, hide a few columns. Click 'Save view' to pin that perspective. Switch to Kanban or Calendar to see the same data differently.
5. Invite your team
Open Members and add teammates as Admin, Manager, Member, or Viewer. Roles map to capabilities; the matrix on the Members page shows what each can do.
04

Building a real workspace

A worked example: a tiny CRM with customers, deals, and a pipeline dashboard.

Model the tables
Create Customers (text name, email, company) and Deals (text title, currency value, single_select stage, date close_date). Make Deals.customer a relation_one to Customers.
Add a rollup
On Customers, add a rollup field 'total_pipeline' over the Deals back-reference that sums Deals.value. Each customer row now shows pipeline at a glance.
Add a formula
On Deals, add a formula 'weighted_value' = value * (stage = 'Won' ? 1 : stage = 'Negotiation' ? 0.6 : 0.2). The engine resolves chained formulas in up to five passes.
Spin up a Kanban
On Deals, switch to Kanban grouped by 'stage'. Drag cards to update status. Save it as a view called 'Pipeline'.
Build a dashboard
Add a Dashboard view: a KPI tile for sum(weighted_value), a bar chart of value by stage, a leaderboard of top customers. Mention it later with @ in the AI Assistant to add more widgets.
Publish a form
On Customers, open Forms and publish a public intake form at /f/$slug. Submissions land as new records, with file uploads and validation handled for you.
05

Using the AI Assistant

A workspace-aware co-pilot on the right rail. It can mention things, confirm actions, and edit your workspace directly.

Open it
Toggle the sidebar from the header, or hit Cmd / Ctrl + . from anywhere inside a workspace.
Mention with @
Type @ to reference a table, view, dashboard, or record. The assistant scopes its reasoning to what you point at instead of guessing.
Ask it to build
Try 'add a bar chart of orders by status to @Sales dashboard' or 'create a Tasks table with assignee, due_date, and status'. It uses tools to apply the change, not just describe it.
Confirm before destruction
Schema edits, bulk updates, and deletes show a confirmation step. Nothing destructive happens silently.
06

Where to go from here

Once the basics click, these are the next stops.

Model your data well
Read the Data layer section: primary fields, relations, lookups vs rollups, formulas, junction tables, and delete rules. This is where Sheetzo gets powerful.
Share safely
Share links and the permissions / roles model let you expose exactly the right slice to teammates, clients, or the public.
Automate the boring parts
Imports, public forms, and email parsing turn manual data entry into a pipeline. Notifications keep the right people in the loop.
Keep it tidy
Archive workspaces and tables you do not need, restore from Trash when you make a mistake, and lean on version history for accidental edits.
Part 1

The data layer

Primary fields, relations, rollups, formulas, and the permission model that ties them together.

01

Primary field

Every table has exactly one primary field - the human-readable label used everywhere a record is referenced.

One per table
When a table is created, the first text field becomes primary. You can promote a different field with 'Set as primary' in the schema editor.
Protected from deletion
The primary field cannot be deleted while it's the active label. Promote another field first, then remove the old one.
Used in chips and pickers
Relation chips, AI mentions, share links, and the record drawer all display the primary field value.
02

Unique record IDs

Every row gets an immutable rec_xxxxxxxx identifier, plus created and updated timestamps.

Auto-generated
IDs are assigned on insert and never change. Safe to use in URLs, formulas, integrations, and import / export round-trips.
Hidden by default
Toggle 'Record ID', 'Created at', and 'Updated at' from the field visibility menu when you need to expose them in a view.
Copyable chips
Click any rec_ chip to copy. The full UUID is preserved server-side; the short form is just for display.
03

Relations

Link records across tables. One-to-many or many-to-many, with a polished picker built for real datasets.

Step 1: Open the source table
Pick the table that will hold the link. Example: in a Deals -> Customers setup, the link lives on Deals (each deal points at one customer). Open Deals and click the '+' at the end of the column header row to add a field.
Step 2: Choose a relation type
Set the field type to 'Relation (one)' if each record links to a single record on the other side, or 'Relation (many)' if it can link to several. Give the field a clear name like 'customer' or 'tags'.
Step 3: Point it at the target table
In the field options, pick the target table from the 'Links to' dropdown. Optionally set a 'Display field' to control which column shows in the chip (defaults to the target's primary field).
Step 4: Save, then link records
Save the field. Back in the grid, click the empty cell in that column and the relation picker opens. Search, select one or more target records, then press Enter or click Done. Chips appear in the cell.
Step 5: See it from the other side
Open any linked record on the target table. The drawer's 'Linked from' section automatically lists every record that points at it - no second field to create.
Single vs many
relation_one stores one linked record; relation_many stores an array. Both render as chips in the grid and drawer. Switch type later by editing the field.
Polished picker
Two-pane popover with debounced search, A-Z and Recent sort, keyboard navigation, multi-select chips, inline 'create new', and a preview pane.
Linked-only filter
When editing a multi-select relation, toggle 'Linked only' to see just the currently selected records.
Stuck? Common gotchas
If the picker is empty, the target table has no records yet - create one first or use 'Create new' inside the picker. If you can't pick a target table, make sure both tables live in the same workspace. If chips show 'rec_...' instead of a name, set a primary field on the target table.
05

Rollups

Aggregate values across a relation_many. Count, Sum, Avg, Min, Max, Percent complete.

Pick a relation and a field
Choose a relation_many on the current table, then a numeric or boolean field on the target. The aggregation runs at read time.
Percent complete
For boolean fields, returns the share of linked records where the value is true. Useful for task lists, checklists, and onboarding.
Composable with formulas
Rollup outputs feed straight into the formula engine, so 'completion %' or 'total revenue' become first-class fields.
06

Formula engine

Compute new fields from local, lookup, and rollup values. Iterative evaluation handles chained formulas.

Local fields
profit = revenue - cost. Reference any field on the same record by its column name.
Lookups and rollups
Read pre-computed values from linked records: customer.tier, items.sum, tasks.percent_complete.
Conditionals
IF(balance > 0, 'Pending', 'Paid'). Five evaluation passes resolve formula-on-formula dependencies.
07

Junction tables

Real many-to-many with metadata on the link itself. Order Items between Products and Orders, with quantity, unit price, and discount.

First-class type
Tables are flagged is_junction with parent IDs. Created through a dedicated tab in the 'Add table' dialog.
Custom metadata
Define any fields on the junction: quantity, price snapshot, discount, notes. They live on the link, not on either parent.
Rollups span junctions
Aggregate junction fields back onto a parent, e.g. order.total = sum(order_items.line_total).
08

Delete rules

Decide what happens to linked data when a record is removed. Restrict, Cascade, or Nullify.

Restrict
Block the delete if any record still references this one. The default for invoice -> customer style relations.
Cascade
Delete dependent records too. Use for owned children: order -> order_items, project -> tasks.
Nullify
Keep dependent records, just clear the link. Use for soft associations: task -> assignee.
09

Relation-aware permissions

Three independent checks per relation: edit the link, see linked records, open linked records.

Edit the relation
Field-level access controls whether the picker accepts changes. Read-only fields render locked chips.
See the linked record
The permission system returns only IDs the caller can view. Hidden links render as 'Restricted' chips.
Open the linked record
Target-table access gates the open-in-tab action and the preview pane. Create-new is gated on edit access to the target.
11

Field type reference

Every field type Sheetzo ships, what it stores, and what it renders as.

text
Single-line string. Default for the primary field on a new table.
long_text
Multi-line string with newline support. Editor opens a textarea.
number
Numeric value. Configurable precision and thousands separator.
currency
Number with a currency code and locale-aware formatting.
percent
Number stored 0-1 or 0-100 depending on field config. Renders with a % suffix.
rating
Integer 0-N rendered as stars. Useful for triage and quality scores.
date
Date or datetime. Drives Calendar view and can power formulas.
single_select
One value from a predefined option list. Renders as a colored chip.
multi_select
Array of values from an option list. Renders as a chip cluster.
checkbox
Boolean. Feeds Percent complete rollups.
url
Validated URL. Renders as a click-out link.
email
Validated email address. Renders as a mailto link.
file
One or more uploaded files, stored in scoped buckets with signed URLs.
relation_one
Single link to another table's record. Rendered as a chip with the target's primary field.
relation_many
Array of links to another table's records. Powers rollups.
lookup
Read-only mirror of a field on a linked record (relation_one only).
rollup
Aggregation across a relation_many target field. Count / Sum / Avg / Min / Max / Percent complete.
formula
Computed expression over local, lookup, and rollup values.
system
Record ID, Created at, Updated at. Hidden by default, toggleable per view.
12

Lookups vs rollups

Both read from linked records. They answer different questions.

Use a lookup
When you want one value from one linked record. order.customer_tier, invoice.customer_email. Requires a relation_one.
Use a rollup
When you want an aggregation across many linked records. order.line_total = sum(items.subtotal), project.percent_complete = percent(tasks.done). Requires a relation_many.
Composability
Both feed the formula engine. profit_margin = (revenue - cost) / revenue where revenue can itself be a rollup.
13

System fields

Synthetic columns every table exposes. Toggle them on when you need them.

Record ID
The immutable rec_xxxxxxxx identifier.
Created at
Timestamp of the original insert.
Updated at
Timestamp of the last write. Refreshed on every save.
Part 2

Product surfaces

Everything users touch on top of the data layer: views, forms, share links, reports, imports, email parsing, and the AI assistant.

01

Views

Same dataset, multiple perspectives. Grid, Kanban, Calendar, Dashboard. Save any configuration as a named view.

Grid
Virtualized rows, inline editing, column visibility, fullscreen mode, drag-resize, and per-column sort. Renders hundreds of thousands of cells without lag.
Kanban
Group by any single-select field. Drag cards between columns to update status. Card body shows the fields you pick.
Calendar
Plot records by a date field. Drag to reschedule. Month and week toggles.
Dashboards
KPI tiles, bar / line / pie charts. Add widgets by picking a table, an aggregation, and a group field. The AI Assistant can add widgets to an existing dashboard via @mention.
Saved views
Pin filters, sorts, hidden columns, and group choices to a view chip. Switch perspectives without losing your work.
02

Public forms

Every table can publish a form at /f/$slug. Validated, file-aware, no auth required.

Schema-driven
Form fields are generated from table fields. Type, required, options, and constraints are enforced server-side via Zod.
File uploads
Multipart submissions accept attachments. Files go to scoped storage and are linked to the new record automatically.
One submission per request
Each POST creates one record with metadata: submitted_at, source slug, IP-aware rate limiting.
04

Reports

A4-optimized, printable reports built from any view. Share via a public URL.

Report builder
Pick a source table or view, choose columns, add a header, footer, and logo. Preview renders at print dimensions.
Public viewer
Tokenized URLs render the same layout for non-members. Print-to-PDF preserves pagination and column widths.
Live data
Reports query the source on every render. No snapshotting, no stale numbers.
05

Imports

Pull data in from CSV, XLSX, Shopify, and other POS exports. Manual column mapping when auto-detect isn't enough.

Universal mapper
The column-mapping dialog reads the incoming header row, suggests a target field per column, and lets you override. Skip columns you don't need.
Platform presets
Shopify Orders, Square POS, and other common report shapes ship with pre-mapped templates so the first import is one click.
Bulk insert
Up to 5,000 rows per import. Validation errors surface per row without aborting the batch.
06

Email parsing

Forward an inbox to Sheetzo. AI extracts structured records from each message.

Workspace inbox
Each workspace has a dedicated inbox route. Incoming emails are listed with sender, subject, and parse status.
AI extraction
Gemini reads the email body (and attachments where possible) and maps fields to the target table's schema.
Review and accept
Parsed records land in a review queue. Approve to insert, edit before inserting, or discard.
07

AI Assistant sidebar

Workspace-aware chat on the right rail. Mentions, confirmations, and direct schema edits.

Mentions
Type @ to reference a table, view, dashboard, or record. The assistant scopes its context to what you mention.
Confirmation flows
Destructive actions (schema changes, bulk edits) show a confirm step before running.
Tools
The assistant can add dashboard widgets, create fields, set primary fields, and more. It edits the workspace directly instead of just describing changes.
08

Workspace lifecycle

Archive, restore, and trash. Nothing is permanently deleted by accident.

Archive
Hide a workspace or table from active lists without deleting. Restorable from the archive section.
Trash
Soft-deleted items live in trash and stop appearing in search, dashboards, AI context, and the home grid.
Restore or purge
Trash entries can be restored to their original location, or permanently purged from the trash view.
10

Themes and tour

Switchable look and feel, plus an opt-in guided tour for new users.

Brutal theme
Toggle a high-contrast, no-rounding theme from the workspace header. The Sheetzo default is the soft / refined look.
Tour button
A light-blue Tour button in the header launches a guided walkthrough on demand. The tour never auto-starts.
Per-workspace sidebar
Left sidebar swaps to a workspace-scoped nav when you enter a workspace, with color-coded accents per section.
11

Filters, sorts, and saved views

Slice any table without losing the slice. Saved views render as pills above the grid.

Filters
Stack any number of field predicates. Equals, contains, is empty, in range, before / after for dates, has any / has all for multi-selects.
Sorts
Multi-column sort with explicit precedence. Drag to reorder. Toggle ascending / descending per column.
Saved views
Pin filters, sorts, hidden columns, group, and surface (Grid / Kanban / Calendar / Dashboard) to a named view chip. Switch perspectives without losing your work.
Per-user defaults
Each member's last-used view is remembered per table automatically.
Part 3

Platform and ops

Auth, roles, RLS posture, storage, backups, record versions, notifications, and feature flags.

01

Auth and roles

Workspace owner, editor, and viewer roles. Backed by user_roles and the has_role security definer function.

Roles per workspace
Each member assignment carries a role: owner, editor, or viewer. Owners manage members and billing; editors mutate data and schema; viewers read.
has_role()
All role checks go through a security definer function that bypasses row-level security to avoid recursion. Never read the roles table directly from a policy.
RLS posture
Every table has row-level security enabled with explicit grants. Workspace-scoped tables filter on member access; sensitive columns add field-level permission checks.
Auth methods
Email and password plus Google sign-in by default. SAML SSO available on request.
02

Storage and signed URLs

File-type fields and form attachments live in scoped buckets, served via short-lived signed URLs.

Per-workspace scoping
Object paths are prefixed with the workspace ID. Bucket policies require an authenticated member to read, or a valid share token for public surfaces.
Signed URLs
The drawer, grid, and reports request a fresh signed URL on render. URLs expire on the order of minutes so leaked links don't grant lasting access.
Public form uploads
Anonymous form submissions write to an isolated path. Files are linked to the new record on successful insert; orphans are cleaned up by a maintenance job.
03

Backups and record versions

Whole-workspace snapshots and per-row history.

Workspace backups
Compact JSON snapshots of schema and data are stored automatically. Trigger manually or on a schedule. Restore replays the snapshot into a new or existing workspace.
Record versions
Every write to a workspace table appends a version record with the before / after payload and the actor. Restore a prior version from the record drawer's history tab.
Retention
Versions are kept until the record is purged from trash. Backups follow the workspace's retention policy.
04

Notifications

In-app notifications for mentions, share invites, comments, and automation results.

Inbox
The notifications table powers the bell icon in the header. Each row has a type, payload, read flag, and target route.
Write paths
Inserts come from trusted server-side events like comments, mentions, and share invites. The user themself cannot insert arbitrary rows.
Delivery
Realtime subscription pushes new rows to the open client. No external email or push yet; that ships behind a feature flag when ready.
05

Feature flags

feature_flags table gates risky or in-progress surfaces. Read via useFeatureFlag.

Per-flag rollout
Each row is keyed by flag name with a global boolean and an optional list of allowed user IDs or workspace IDs.
useFeatureFlag
Client hook reads from a public, cached query. Always call it at the top of the component, never inside a conditional, to keep hook order stable.
Server-side check
Server functions read feature_flags directly with the service-role client when needed. Never trust the client for gating destructive paths.
Part 4

Developer reference

Public API endpoints, the RPC catalog, and the server-function authoring pattern.

01

Public API endpoints

Webhooks, cron, and public reads. Always signature-verified.

Routing convention
Public endpoints live under the /api/public path so external callers can reach them. Each handler verifies the caller before processing any data.
Signature verification
Every handler verifies an HMAC signature using a secret key before reading the body. Unsigned or mismatched requests get a 401.
Stable URLs
Production and preview deployments have stable URLs. Use these when configuring external services and scheduled jobs.
02

RPC catalog

Database functions that power the relational features.

ws_search_records
ILIKE search on the primary field, server-side sort and pagination. Returns rows plus a total count for the picker.
ws_get_records_by_ids
Resolve display labels for a set of record IDs. Used to render selected chips that aren't on the current search page.
ws_ensure_search_index
Idempotent search index creation on the primary field. Called the first time a relation picker opens against a table.
ws_set_primary_field
Promotes a field to primary. Validates the field is text-shaped and refuses to leave a table without a primary.
ws_list_back_references
Returns every record that links to the target, grouped by source table and field. Permission-aware.
ws_filter_accessible_record_ids
Filters a set of record IDs down to those the caller can read. Used by the picker, back-references, and lookup resolution.
ws_delete_record
Recursive delete that enforces per-relation rules: Restrict aborts, Cascade removes dependents, Nullify clears links. Scrubs incoming references.
ws_create_junction_table
Creates a junction table with the two parent relations and any extra metadata fields in one call.
03

Server-function pattern

Typed RPC from the client to the server. Auth via middleware.

Authoring
Export a typed server function with input validation and a handler. Keep them in client-safe paths, not in server-only directories.
Auth middleware
Add auth middleware to gate the function. The context is populated for the authenticated caller, including their user ID and claims.
Calling
Use the framework's server-function hook to call from a component or event handler. Never call a protected function from a public route's loader; SSR has no session.
Env access
Read secrets inside the handler body, never at module scope. Public config goes through the framework's public env mechanism.
Part 5

Reference

Changelog, frequently asked questions, glossary, and the keyboard shortcuts cheatsheet.

01

What's new

Recent shipped work, newest first. Anchor your team on the same timeline.

Indexed search for relation pickers
pg_trgm GIN indexes, server-side pagination, 250ms debounce, and chip-resolution by ID. Relation pickers now scale to 500k+ row tables.
Permissions layer for relations
Field, record, and target-table checks gate edit, view, and open actions independently. Restricted links render as locked chips.
Delete rules
Restrict, Cascade, and Nullify on every relation. Enforced recursively at the database level.
Junction tables
First-class many-to-many with metadata. Dedicated tab in the 'Add table' dialog.
Formula engine
Local, lookup, and rollup references with five-pass iterative evaluation for chained formulas.
Rollup engine
Count, Sum, Avg, Min, Max, Percent complete across relation_many fields.
Reverse link engine
Automatic back-references in the record drawer, permission-aware and cleanup-aware on delete.
Unique record IDs and system fields
Immutable rec_xxxxxxxx, plus toggleable Created at / Updated at columns.
Primary fields
Every table has exactly one. Promote via 'Set as primary' in the schema editor; deletion is blocked while active.
Two-layer navigation
Workspace-scoped sidebar with color-coded sections; favorites pinned above recents.
Runway-inspired marketing redesign
Refreshed homepage, auth, marketplace, and docs with parallax hero icons and lime accents.
02

FAQ

Short answers to the questions we hear most.

Is Sheetzo a spreadsheet or a database?
Both. The UI feels like a spreadsheet, but the storage is a relational database with typed fields, relations, formulas, rollups, and row-level permissions.
How many rows can a table hold?
Tables are backed by Postgres. Relation pickers stay fast at 500k+ rows thanks to trigram indexes and server-side pagination. Imports cap at 5,000 rows per batch.
Can non-members fill out a form?
Yes. Public forms at /f/$slug accept anonymous submissions, including file uploads, with server-side Zod validation and IP-aware rate limiting.
How do share links work?
Each token scopes access to a single record, view, table, workspace, or report. Public viewers are read-only. Revoke any token from the share dialog.
What happens when I delete a linked record?
The relation's delete rule decides: Restrict blocks the delete, Cascade removes dependents, Nullify clears the link and keeps the dependent row.
Can I undo a delete?
Workspaces and tables move to Trash and can be restored. Records can be recovered from version history until purged.
Does the AI assistant edit my data?
Yes, through tools like add_dashboard_widget and create_field. Destructive actions surface a confirmation step before running.
Where is data stored?
Lovable Cloud, with row-level security on every workspace table and field-level permissions for sensitive columns.
03

Glossary

Shared vocabulary. If a teammate uses one of these terms, this is what they mean.

Primary field
The one field per table used as the record's human label, shown in chips, mentions, and share links.
Record ID
Immutable rec_xxxxxxxx identifier assigned on insert. Safe for URLs, formulas, and integrations.
Relation
A typed link from a row in one table to one (relation_one) or many (relation_many) rows in another.
Back-reference
The reverse side of a relation. If A links to B, B's drawer shows A under 'Linked from'.
Lookup
A read-only field that pulls a value from a linked record, e.g. order.customer_tier.
Rollup
An aggregation across a relation_many target field. Count, Sum, Avg, Min, Max, or Percent complete.
Formula
A computed field expressed over local, lookup, and rollup values. Resolved in up to five passes.
Junction table
A table whose rows represent the link between two parents, with extra metadata. Order Items between Orders and Products.
Delete rule
Per-relation policy that runs when a referenced record is removed: Restrict, Cascade, or Nullify.
View
A saved configuration of filters, sort, hidden columns, group, and surface (Grid, Kanban, Calendar, Dashboard).
Share token
Opaque string that grants scoped, read-only access to a record, view, table, workspace, or report.
Workspace
A grouped set of tables, views, dashboards, forms, and members with shared permissions.
04

Keyboard shortcuts

Hands-on-keyboard moves that pay back the muscle memory.

Global
Cmd / Ctrl + K open global search. Cmd / Ctrl + . toggle the AI Assistant sidebar. Esc close any open drawer, dialog, or popover.
Grid navigation
Arrow keys move the active cell. Enter open the cell editor. Tab / Shift + Tab move horizontally. Cmd / Ctrl + Click to multi-select rows.
Editing
Enter commit and move down. Shift + Enter newline inside a long-text cell. Esc cancel edit. Cmd / Ctrl + Z undo last change.
Relation picker
Arrow keys move the highlight. Enter pick the highlighted record. Tab pin the preview pane. Cmd / Ctrl + Enter create a new record inline.
Record drawer
J / K cycle to the previous / next record. Cmd / Ctrl + Enter save and close. Esc close without saving.
AI Assistant
@ mention a table, view, dashboard, or record. Cmd / Ctrl + Enter send the message. Up arrow in an empty input recalls the last prompt.

Ready to model your operation?

Spin up a workspace, import a spreadsheet, or start from a template. The data layer described here is on every plan.