# Get started (/docs/get-started)
An **Enjab tool** is a web app that two Enjab services take care of for you:
* **[Sign in with Enjab Auth](/docs/sign-in-with-enjab)** handles *who the user is* and
*whether they may use your tool*. You never build a login screen or touch a password.
* **[Enjab UI](/docs/enjab-ui)** gives you the *look* - a themed component registry and a
dashboard shell, so every Enjab tool feels like one product.
You build the part in the middle: your tool's actual features. Everything else is
provided.
## The shape of an Enjab tool [#the-shape-of-an-enjab-tool]
1. It lives on an **`enjab.ae`** domain (e.g. `yourtool.enjab.ae`). Auth refuses any
other domain.
2. The instant a signed-out visitor touches any page, they are redirected to Enjab to
sign in. No login button, no login page of your own.
3. Once signed in, you key all your own data by the user's stable Enjab id (`sub`).
4. Your dashboard uses the Enjab UI shell, so the sidebar, account block, and the
"an Enjab product" byline are consistent with every other tool.
## Fastest path [#fastest-path]
### Register the tool (one time) [#register-the-tool-one-time]
An Enjab admin adds your tool in [auth.enjab.ae/admin](https://auth.enjab.ae) and hands
you a `ENJAB_CLIENT_ID` + `ENJAB_CLIENT_SECRET`. See
[Sign in with Enjab Auth → register](/docs/sign-in-with-enjab) for the exact steps.
### Wire up login [#wire-up-login]
Drop in the four reference files (`lib/enjab-auth.ts`, the callback route, the logout
route, and `proxy.ts`). Set your four environment variables. That is the whole
integration - copy them from [Sign in with Enjab Auth](/docs/sign-in-with-enjab).
### Add the UI [#add-the-ui]
Install the Enjab UI chrome and theme, then build your screens with the registry
components so your tool matches the rest of Enjab. See [Enjab UI](/docs/enjab-ui).
## Handing this to an agent [#handing-this-to-an-agent]
Give your coding agent this site's [`/llms.txt`](/llms.txt) (or the specific page's raw
markdown) and the task. The pages are written so the agent can do each step end to end.
# Overview (/docs)
Welcome to **Enjab Developers** - the single source of truth for building on Enjab.
Everything an Enjab tool needs is here: how to add **Sign in with Enjab Auth**, how to ship
on-brand UI with the **Enjab UI** design system, and how to bring an existing tool up to
the latest standards. One central place, kept current, for every Enjab tool that exists
today and every one we build next.
## Built for agents first [#built-for-agents-first]
These docs are written so a **coding agent** can read them and do the work, with humans
reading the same pages. Every page is a normal markdown file you can fetch raw:
| Endpoint | What it returns |
| ---------------------------------- | ----------------------------------------- |
| [`/llms.txt`](/llms.txt) | The index of every page, with links |
| [`/llms-full.txt`](/llms-full.txt) | Every page concatenated into one document |
| `/llms.mdx/docs//content.md` | A single page, raw markdown |
Point an agent at `/llms.txt` and let it pull the pages it needs. No separate "agent
version" of the docs - the page you read is the page the agent reads.
## The tools [#the-tools]
## Where to start [#where-to-start]
If you are building a new tool, read [Get started](/docs/get-started) first - it covers
how the pieces fit together and the fastest path to a working integration. If you are an
agent, start at [`/llms.txt`](/llms.txt).
# Enjab Auth (/docs/changelog/enjab-auth)
Changes to [Sign in with Enjab Auth](/docs/sign-in-with-enjab), newest first. The current
contract version is `2026.06.07a`. To bring a tool up to date, see
[Update an existing tool](/docs/update-an-existing-tool/auth) or use the combined update
prompt on the [Changelog overview](/docs/changelog).
## Super admin can change a user's email [#super-admin-can-change-a-users-email]
`Enjab Auth` · 7 Jun 2026
**Changed.** A super admin can change any user's email (including their own) from the Enjab Auth admin. The stable user id (`sub`) never changes, so nothing keyed by `sub` breaks. Regular users cannot change their own email.
**Apply.** Key your own records by `sub`, never by email. Mirror the email from `/userinfo` on every request (the same place you read `name`), so an admin email change reflects in your tool immediately.
## Stronger accounts: password policy, forced first change, one super admin [#stronger-accounts-password-policy-forced-first-change-one-super-admin]
`Enjab Auth` · 7 Jun 2026
**Changed.** Enjab Auth now enforces account security centrally, none of which your tool implements: a strong password policy (12 to 24 characters, with an uppercase letter, a lowercase letter, a number, a symbol, and never the person's name), a forced password change on first login and after any admin reset (the user cannot continue until they set a new password, before two-factor), mandatory TOTP two-factor, and exactly one super admin per organization. Users can change their own password later from Settings on the hub.
**Apply.** Nothing in your tool. All of this happens at auth.enjab.ae before a token is ever issued; your tool still just receives the user object.
## Disabled accounts are blocked at the door, is\_active removed [#disabled-accounts-are-blocked-at-the-door-is_active-removed]
`Enjab Auth` · 7 Jun 2026
**Changed.** A disabled account is now stopped wherever it appears, with a plain "your account is disabled" message: at login (signed out, not let in), on the hub, and on the consent screen. Because a tool can therefore only ever receive an active user, the `is_active` field is removed from the user object (token response and `/userinfo`), the `EnjabUser` type, and the OpenID `claims_supported` list.
**Apply.** Delete `is_active` from your `EnjabUser` type and any code that read it (it was always `true`). No other change is needed.
## Redirect host locked to the domain, path is editable [#redirect-host-locked-to-the-domain-path-is-editable]
`Enjab Auth` · 7 Jun 2026
**Changed.** A tool's `redirect_uri` host is locked to its registered domain; you choose only the path (default `/api/auth/callback`). Changing a tool's domain in admin severs the old domain: it drops the old redirect from the allowlist and revokes that tool's sessions.
**Apply.** Keep your callback on your registered `enjab.ae` domain. If an admin changes your tool's domain, update `ENJAB_REDIRECT_URI` to match and re-authenticate.
## Central sign-out revokes every issued token [#central-sign-out-revokes-every-issued-token]
`Enjab Auth` · 6 Jun 2026
**Changed.** Signing out of Enjab Auth itself (the hub) now revokes every access token issued to every tool. Each tool loses access on its next `/userinfo` check.
**Apply.** Re-validate every request with `getUser()` (it calls `/userinfo` fresh, `cache: "no-store"`). Never cache the user object beyond the request, or a signed-out person keeps working.
## /userinfo re-checks tool access on every call [#userinfo-re-checks-tool-access-on-every-call]
`Enjab Auth` · 6 Jun 2026
**Changed.** `/userinfo` re-checks that the user still has access to your tool, not just that the account exists. A revoked role or grant returns `401` immediately, the token alone is never enough.
**Apply.** Read the user fresh on each request and treat a `401` as signed-out (redirect to `/authorize`). Do not trust a cached user or cookie claims.
## Confirmed, per-tool sign-out [#confirmed-per-tool-sign-out]
`Enjab Auth` · 6 Jun 2026
**Changed.** Sign-out is per-tool and confirmed on Enjab Auth. Your "Sign out" button navigates to `/api/auth/logout`, which sends the user to Enjab Auth's confirm page; confirming clears only your tool's session, never the central session.
**Apply.** Use the logout route from the [Next.js reference](/docs/sign-in-with-enjab/nextjs). Never call a sign-out or clear the session yourself.
## Roles are sent only to role-aware tools [#roles-are-sent-only-to-role-aware-tools]
`Enjab Auth` · 6 Jun 2026
**Changed.** `roles` and `is_super_admin` are included in the user object only if an admin marks your tool role-aware; otherwise the keys are absent.
**Apply.** Treat access as binary. Do not gate features by role unless your tool is role-aware. See [Roles](/docs/sign-in-with-enjab/roles).
## User name plus greeting and consent screen [#user-name-plus-greeting-and-consent-screen]
`Enjab Auth` · 6 Jun 2026
**Changed.** The user object includes the person's `name` (set in Enjab Auth admin). Enjab Auth shows a greeting and consent screen on the way in.
**Apply.** Greet the user with `user.name`. Do not build a consent screen; Enjab Auth owns it.
## Drop-in dashboard shell wired to Enjab Auth [#drop-in-dashboard-shell-wired-to-enjab-auth]
`Enjab Auth` · 6 Jun 2026
**Changed.** The reference now includes a complete dashboard shell: the Enjab UI sidebar wired to the signed-in user (real name, email, sign out, byline).
**Apply.** Build your dashboard from the shell. See [Dashboard shell](/docs/sign-in-with-enjab/dashboard).
## Redirects restricted to enjab.ae [#redirects-restricted-to-enjabae]
`Enjab Auth` · 6 Jun 2026
**Changed.** Enjab Auth refuses to send a code to any `redirect_uri` that is not https on a registered `enjab.ae` domain. This is what stops a random site from harvesting a login.
**Apply.** Host your tool on an `enjab.ae` domain and register the exact redirect URI in admin.
## Sign in with Enjab Auth published (OAuth2 + RBAC) [#sign-in-with-enjab-auth-published-oauth2--rbac]
`Enjab Auth` · 6 Jun 2026
**Changed.** Initial release: OAuth 2.0 authorization-code flow, the token response returns the user profile, `/userinfo` for fresh reads, and org-level role-based access control.
**Apply.** Integrate per [Sign in with Enjab Auth](/docs/sign-in-with-enjab).
# Enjab UI (/docs/changelog/enjab-ui)
Changes to the [Enjab UI](/docs/enjab-ui) design system, newest first. To bring a tool up
to date, see [Update an existing tool](/docs/update-an-existing-tool/ui) or use the
combined update prompt on the [Changelog overview](/docs/changelog).
## 2026.06.07e: Buttons must not change size on hover or click [#20260607e-buttons-must-not-change-size-on-hover-or-click]
`Enjab UI` · 7 Jun 2026
**Changed.** New rule: a button must never change size on hover, focus, or active/selected state (no layout shift). Change only color or background. The usual cause is a border toggling on/off on an auto-width button; keep a border in every state (`border border-transparent` where you don't want a visible one). See [Foundations](/docs/enjab-ui/foundations).
**Apply.** Audit selected/active button states for border, padding, or scale changes that resize the box.
## 2026.06.07d: Small screens must have full functionality [#20260607d-small-screens-must-have-full-functionality]
`Enjab UI` · 7 Jun 2026
**Changed.** Strengthened the responsive rule: a phone must do everything desktop can, exactly. Collapse or restyle to fit (stack, hamburger, icon buttons, scroll), but never hide, drop, or break a control on small screens. If a labelled button doesn't fit, make it an icon button. See [Foundations](/docs/enjab-ui/foundations).
**Apply.** Audit each dashboard at 360px: every action reachable and working, tap targets at least `size-9`.
## 2026.06.07c: No em-dashes [#20260607c-no-em-dashes]
`Enjab UI` · 7 Jun 2026
**Changed.** New rule: never use an em-dash (`—`) or en-dash (`–`) anywhere (UI copy, headings, code, comments, content). Use a comma, period, colon, parentheses, or a spaced hyphen instead. See [Foundations](/docs/enjab-ui/foundations).
**Apply.** Sweep your copy and replace any `—` / `–`.
## 2026.06.07b: Custom 404 page required [#20260607b-custom-404-page-required]
`Enjab UI` · 7 Jun 2026
**Changed.** New `@enjab-ui/not-found` and a new rule: every Enjab tool ships a custom `app/not-found.tsx` (the tool's gradient mark, `404`, **Page not found**, a back-home button, and the byline), never the framework default. See [Foundations](/docs/enjab-ui/foundations).
**Apply.** Install it and edit the glyph + home link: `npx shadcn add @enjab-ui/not-found`.
## 2026.06.07a: Browser tab titles read "Page - Service" [#20260607a-browser-tab-titles-read-page---service]
`Enjab UI` · 7 Jun 2026
**Changed.** New rule: every browser tab title reads `Page - Service` (for example `Sign in - Enjab Auth`), never the bare service name. Set a title template in the root layout (`title: { default, template: "%s - Service" }`) and give each page its own short title; client pages use a tiny server `layout.tsx`. See [Foundations](/docs/enjab-ui/foundations).
**Apply.** Add the title template to your root layout and a `title` to each page. The home page can keep the bare service name.
## 2026.06.06l: Dashboards are responsive (phone-usable) [#20260606l-dashboards-are-responsive-phone-usable]
`Enjab UI` · 6 Jun 2026
**Changed.** The shell is responsive now: `@enjab-ui/sidebar` collapses to a hamburger drawer below `lg`, `dashboard-shell` stacks, `page-header` tightens. `data-table` already scrolls. New rule: landing pages fully responsive; dashboards desktop-optimized but phone-usable (stack grids, `p-4 sm:p-6`), never desktop-only.
**Apply.** Re-install: `npx shadcn add @enjab-ui/sidebar @enjab-ui/dashboard-shell @enjab-ui/page-header`. Make your content stack on small screens (`grid-cols-1 sm:grid-cols-2 ...`).
## 2026.06.06k: Tools show their OWN brand (Enjab logo moves to the byline) [#20260606k-tools-show-their-own-brand-enjab-logo-moves-to-the-byline]
`Enjab UI` · 6 Jun 2026
**Changed.** New `@enjab-ui/app-mark`: a tool's own mark (the gradient favicon square + the tool name). The sidebar brand header now shows this (pass `appName` + `appIcon`), not the Enjab logo. The Enjab parent logo now appears only in the "an Enjab product" byline. Demo dashboard + landing updated.
**Apply.** Install `@enjab-ui/app-mark` and pass `appName` + `appIcon` (the same glyph as your favicon) to `@enjab-ui/sidebar`. Re-install sidebar. Use the Enjab logo only in the byline.
## 2026.06.06j: Favicon and in-app icon must match [#20260606j-favicon-and-in-app-icon-must-match]
`Enjab UI` · 6 Jun 2026
**Changed.** New rule: a tool's favicon and any in-app icon or brand mark must be the SAME image. The favicon glyph is canonical; mirror it into one small component so the tab icon and the on-screen mark cannot drift. Also: customize the favicon glyph with inline SVG (Lucide React components do not render in the icon generator).
**Apply.** When you set a custom favicon glyph, render the identical mark (same gradient square + glyph) anywhere the app shows its own icon.
## 2026.06.06h: Favicon is now customizable (swap the letter or use an icon) [#20260606h-favicon-is-now-customizable-swap-the-letter-or-use-an-icon]
`Enjab UI` · 6 Jun 2026
**Changed.** `@enjab-ui/favicon` is code-generated: `app/icon.tsx` + `app/apple-icon.tsx` render the Enjab gradient square with a glyph. Edit the `GLYPH` constant to use a different letter or paste an icon's inline SVG (Lucide React components do not render in the generator). PNG output, so it works in Safari with no separate `.ico`. Default stays "E".
**Apply.** Re-install: `npx shadcn add @enjab-ui/favicon`. Delete any old `app/icon.svg` so it does not clash. To brand a tool, set `GLYPH` in `app/icon.tsx` + `app/apple-icon.tsx`.
## 2026.06.06g: Buttons show a loading state [#20260606g-buttons-show-a-loading-state]
`Enjab UI` · 6 Jun 2026
**Changed.** Button gained a `loading` prop: it disables itself and shows a spinner while an async action runs. New rule: any button whose action takes time must use it (or `useFormStatus` for server-action forms), never stay clickable and silent.
**Apply.** Re-install: `npx shadcn add @enjab-ui/button`. Use `` for slow actions.
## 2026.06.06f: Alert component (success / info / warning / danger) [#20260606f-alert-component-success--info--warning--danger]
`Enjab UI` · 6 Jun 2026
**Changed.** New `@enjab-ui/alert`: one consistent in-page message box in four tones. Icon + title carry the meaning, so status is never color alone. Replaces hand-rolled colored notice boxes.
**Apply.** Install: `npx shadcn add @enjab-ui/alert`. Use it for persistent, view-tied messages (form errors, warnings, success/info notices). Keep using a toast for transient feedback and `status-pill` for per-row status.
## 2026.06.06e: Tables are strict now (no more ugly tables) [#20260606e-tables-are-strict-now-no-more-ugly-tables]
`Enjab UI` · 6 Jun 2026
**Changed.** `data-table` is fully self-styled: comfortable rows, mono uppercase headers, soft line separators, and a canvas hover, all enforced inside the component. It no longer inherits the cramped shadcn table defaults, so every Enjab tool's tables look identical to the demo dashboard. The base table primitive is Enjab-styled too (same padding, header, borders, hover), so even a raw table cannot drift.
**Apply.** Re-install: `npx shadcn add @enjab-ui/data-table`. Build all tables from it (never hand-roll a table).
## 2026.06.06d: Account block is now identical everywhere [#20260606d-account-block-is-now-identical-everywhere]
`Enjab UI` · 6 Jun 2026
**Changed.** `sidebar-footer` always renders the same two lines (display name + email + Sign out); derives the name from the email when none is given, so it cannot drift between tools.
**Apply.** Re-install: `npx shadcn add @enjab-ui/sidebar-footer @enjab-ui/sidebar`.
## 2026.06.06c: Ready dashboard chrome (sidebar, shell, header, table) [#20260606c-ready-dashboard-chrome-sidebar-shell-header-table]
`Enjab UI` · 6 Jun 2026
**Changed.** New `@enjab-ui/sidebar`, `dashboard-shell`, `page-header`, `data-table` so every tool's chrome is identical. `logo` now loads from the hosted URL; `sidebar-footer` handles email-only accounts.
**Apply.** Build dashboards from these (do not hand-roll the sidebar, topbar, or table): `npx shadcn add @enjab-ui/sidebar @enjab-ui/dashboard-shell @enjab-ui/page-header @enjab-ui/data-table`. Re-install `logo` + `sidebar-footer` for the fixes.
## 2026.06.06b: Instant navigation with skeletons [#20260606b-instant-navigation-with-skeletons]
`Enjab UI` · 6 Jun 2026
**Changed.** Screens open instantly with a Skeleton while data loads, never a blank or frozen page.
**Apply.** Add a `loading.tsx` to every data-fetching route, with a skeleton that mirrors the layout (`animate-pulse` on `bg-muted`, no layout shift).
## 2026.06.06: Favicon needs a raster for Safari [#20260606-favicon-needs-a-raster-for-safari]
`Enjab UI` · 6 Jun 2026
**Changed.** The favicon rule then required a raster, not just SVG, because Safari ignores SVG-only favicons (blank tab). Superseded by the code-generated PNG favicon (see 2026.06.06h).
**Apply.** Move to the code-generated favicon: `npx shadcn add @enjab-ui/favicon`.
## 2026.06.05d: Favicon required [#20260605d-favicon-required]
`Enjab UI` · 5 Jun 2026
**Changed.** New `@enjab-ui/favicon`. Every Enjab project must ship a favicon, no exceptions.
**Apply.** Add it: `npx shadcn add @enjab-ui/favicon`.
## 2026.06.05c: Bigger Enjab byline logo [#20260605c-bigger-enjab-byline-logo]
`Enjab UI` · 5 Jun 2026
**Changed.** The "an Enjab product" byline logo is larger for legibility.
**Apply.** Re-install: `npx shadcn add @enjab-ui/enjab-byline` (and `@enjab-ui/sidebar-footer`).
## 2026.06.05b: Required sidebar footer + Enjab byline [#20260605b-required-sidebar-footer--enjab-byline]
`Enjab UI` · 5 Jun 2026
**Changed.** New `@enjab-ui/sidebar-footer`: account block (avatar, email, sign out) plus the byline. New `@enjab-ui/enjab-byline`: standalone byline for dashboards with no sidebar.
**Apply.** Every dashboard must show the byline. Sidebar: put `sidebar-footer` at the very bottom. No sidebar: place `enjab-byline` anywhere.
## 2026.06.05a: Typography: Inter Display headings [#20260605a-typography-inter-display-headings]
`Enjab UI` · 5 Jun 2026
**Changed.** Headings use Inter Display, body Satoshi, data Fragment Mono (matches enjab.ae). Earlier builds wrongly used Satoshi for headings.
**Apply.** Headings must use the heading font (`font-heading` or any `h1`-`h6`), never Satoshi. Re-apply the theme: `npx shadcn add https://ui.enjab.ae/r/theme.json`.
## 2026.06.04: Enjab UI registry published [#20260604-enjab-ui-registry-published]
`Enjab UI` · 4 Jun 2026
**Changed.** Initial registry: `theme`, `button`, `status-pill`, `stat-card`, `logo`, `reveal`.
**Apply.** Set up per the [Enjab UI](/docs/enjab-ui) docs.
# Overview (/docs/changelog)
The single, central changelog for the Enjab platform. Each entry says what changed and the
exact action to adopt it. Pick the area you depend on, or use the one prompt below to bring
a tool up to date on everything at once.
## Update everything, one prompt [#update-everything-one-prompt]
Hand this to a coding agent to bring a tool up to date on both Enjab UI and Enjab Auth. It
reads the central docs, works out what the project has not adopted, and applies only that.
```text
Update this project to the latest Enjab standards (UI and Auth). Read
https://developers.enjab.ae/llms.txt and the changelog at
https://developers.enjab.ae/docs/changelog (both the Enjab UI and the Enjab Auth pages),
then apply ONLY the changelog entries this project has not adopted yet.
For Enjab UI: re-install changed components with `npx shadcn add @enjab-ui/`
(overwrite) and re-apply the theme with `npx shadcn add https://ui.enjab.ae/r/theme.json`
if tokens changed.
For Enjab Auth: re-sync the drop-in reference files (lib/enjab-auth.ts, the callback and
logout routes, proxy.ts) and re-check the integration rules (re-validate every request via
/userinfo with cache: "no-store", no login UI of your own, confirmed per-tool sign-out,
access is binary unless the tool is role-aware).
Do not refactor or restyle anything else. Keep the change surface minimal.
```
Updates are not refactors. Apply only the entries the project has not adopted, and leave
the rest of the codebase exactly as it is. For a focused update of one area, see
[Update an existing tool](/docs/update-an-existing-tool).
# Branding and favicon (/docs/enjab-ui/branding)
## Favicon setup [#favicon-setup]
Every Enjab tool ships the favicon via `@enjab-ui/favicon`. Install it once:
```sh
npx shadcn@latest add @enjab-ui/favicon
```
This adds `app/icon.tsx` and `app/apple-icon.tsx` (code-generated PNG icons: the Enjab gradient square plus a glyph). Safari renders these natively, so no separate `.ico` is needed.
### Edit the glyph [#edit-the-glyph]
Open `app/icon.tsx` and find the `GLYPH` constant at the top. Replace it with a letter or paste an icon's inline SVG:
```tsx title="app/icon.tsx"
const GLYPH = "E"; // Change to your letter, or paste an icon's raw