Jump to content
Visit project

Glosario,

A collaborative glossary for everyone

8 minutes read
Technologies used
  • Better Auth
  • Drizzle ORM
  • Hono
  • PostgreSQL
  • React 19
  • shadcn/ui
  • TanStack Router
  • tRPC
  • Turborepo

DLAs

Since day one of my career I've been drowning in TLAs — Three Letter Abbreviations. Every company has its own alphabet soup of internal jargon that everyone pretends to understand and nobody bothers to define.

It's not just corporations either. At the Master Digital Design where I help teach, students get buried under an avalanche of terminology from day one — and half the room is quietly Googling words mid-lecture rather than admitting they have no idea what's being said.

The pattern is always the same: the vocabulary exists, the people exist, but the shared understanding doesn't. No matter what kind of organization you are at, there's a gap between the words people use and what they actually mean by them.

Glosario is my attempt to close that gap — one term at a time.

Domains, not just one big pile

Organizations are split into domains — teams that each own their slice of the glossary. The engineering team defines what deployment means to them; the marketing team does the same. Tags from one domain can be referenced across the whole organization, making it easy to discover where terminology overlaps or, more often, quietly conflicts.

Each term lives in exactly one domain and goes through an explicit approval workflow before it's visible to anyone else.

Glossary overview with term statuses

Terms that earn their place

A term doesn't just appear in the glossary. It has to earn it.

Every term starts as a draft — a scratchpad for whoever first noticed the word was causing confusion. When it's ready, it moves to pending, waiting for a domain curator to review and approve or reject it.

Only approved terms are visible to the rest of the organization. Everything else stays in the domain's own workspace, quietly brewing.

Definitions as a living document

Once a term is approved, its definition is not set in stone. Any team member can submit a suggestion — a proposed rewrite — which a domain curator can accept or reject.

Accepted suggestions become a new immutable revision. Every revision is stored, so you can always trace how a definition evolved and who changed it. No more “wait, what did this used to say?”

// A term has many revisions; the highest version is current
export const definitionRevision = pgTable("definition_revision", {
  id: text("id").primaryKey(),
  termId: text("term_id").references(() => term.id, { onDelete: "cascade" }),
  contentJson: jsonb("content_json").notNull(), // rich-text AST
  plainText: text("plain_text").notNull(),
  version: integer("version").notNull(),
  createdById: text("created_by_id").references(() => user.id),
  createdAt: timestamp("created_at").defaultNow().notNull(),
});
Term detail with revision history and suggestions

Unclear? Say so.

The biggest enemy of a glossary is false confidence — people nodding along to a definition they don't actually understand.

Glosario lets any user flag a term as unclear with a structured reason: too vague, scope unclear, conflicts with another term, missing an example, outdated, or just plain hard to understand.

Clarifications are attached to a specific definition version, so domain curators know exactly which revision triggered the confusion. When the definition is improved, the clarification is resolved. Clean.

export const clarificationReasonEnum = pgEnum("clarification_reason", [
  "too_vague",
  "scope_unclear",
  "conflicts",
  "missing_example",
  "outdated",
  "hard_to_understand",
  "other",
]);
 
// Only one active (unresolved) clarification per user per term
uniqueIndex("clarification_user_term_active_idx")
  .on(table.userId, table.termId)
  .where(sql`resolved = false`),

Terms talk to each other

Terms rarely exist in isolation. A glossary that treats them as isolated entries misses half the picture.

In Glosario, any user can link two terms together. Links are crowd-validated — other users vote to reinforce a connection they agree with. The vote count makes it easy to see which relationships the team actually considers meaningful versus someone's half-baked idea at 4pm on a Friday.

Term relationships, voted on by the team
Related terms panel showing crowd-voted term relationships in glosario

More than a CRUD app

At some point the project stopped being a simple glossary tool and started becoming a proper SaaS product. I only have myself to blame.

Glosario has a full permission model across two axes — your organization role (owner, admin, member) and your domain role (curator, author, reader). These combine to determine what you can see and do, down to individual actions on individual resources.

// The same function works on both frontend (hide the button)
// and backend (throw FORBIDDEN). No permission drift.
export const can = <R extends Resource>(
  ctx: PermissionContext,
  resource: R,
  action: Action<R>
): boolean => {
  // Org-level access first (owners and admins have broad reach)
  if (ctx.orgRole && isValidOrgRole(ctx.orgRole)) {
    const permissions = orgRolePermissions[ctx.orgRole][resource];
    if (permissions?.includes(action as string)) return true;
  }
 
  // Domain-level access for scoped resources
  if (ctx.domainRole && isValidDomainRole(ctx.domainRole)) {
    const permissions = domainRolePermissions[ctx.domainRole][resource];
    if (permissions?.includes(action as string)) return true;
  }
 
  return false;
};

A single pure function. No database calls, no side effects. On the server it enforces; on the client it decides whether a button even renders. The permission model can't drift because there is only one source of truth.

And then I added plans

Free, Core, Scale, Enterprise. Audit logs, analytics, API access, and SSO all gated behind higher tiers. Billing runs through Polar.

Enterprise customers get outbound webhooks — HMAC-SHA256 signed payloads — so they can react to term approvals, definition changes, or anything else happening in their glossary. Every delivery attempt is tracked with retry state, so they can debug why their integration stopped working at 2am.

At this point it is very much a real product. A weird, niche, glossary product — but a real one.

Does your team speak the same language?

If you've ever sat in a meeting where half the room meant one thing and the other half meant something else — and nobody said a word — Glosario was built for you.

Give it a try. It's free to get started, and your first glossary takes about two minutes to set up.