Table conventions in Gista.js
Every table in Gista.js follows a few conventions. You don't have to memorize them — the helpers handle the details — but knowing what each column does will help you understand the code.
id — internal primary key
Every table has an id column: an auto-incrementing integer (1, 2, 3, ...). It's the primary key the database uses to identify rows. You use it internally — in foreign keys, in queries, and in model methods like findByID.
For internal apps or trusted users, exposing integer IDs in URLs is perfectly fine — Rails has done this as the default for decades. But for apps where users don't fully trust each other — think SaaS, marketplaces, or any multi-tenant product — sequential IDs can leak information. If a user sees /forms/42, they can guess /forms/41 or /forms/43 and potentially access someone else's data. Gista.js gives you public_id for this.
public_id — safe to share
It's a random hex string like a7f3b9c1e2d4 — generated automatically when a row is created. This is the ID you put in URLs, API responses, and anything a user can see. It doesn't reveal order or count, and it can't be guessed.
The model gives you findByPublicID to look up rows by this column.
bag — flexible JSON column
Tables can include a bag column — a JSON text field for storing loosely-structured data. Think of it as a junk drawer for your table: a place to toss extra fields before you know exactly what shape they'll take.
Why? Early on, you're figuring things out. Maybe your notes need a color field. Maybe they don't. Adding and removing real columns means changing the database structure each time — that's friction when you're still experimenting. With bag, you just drop new fields into the JSON object and move on.
Once a field proves its worth and you're using it in queries or filters, promote it to a real column. bag is the staging area, not the final home.
Each table defines a typed Bag interface (like NoteBag) so your code still knows what to expect inside the JSON — you get autocompletion and type checking even for the flexible stuff.
created_at / updated_at — automatic timestamps
These columns record when a row was created and last updated. They're set automatically — created_at when the row is inserted, and both default to the current time. You never need to pass them manually.