@xeplr/cli 0.1.5 → 0.1.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -4,9 +4,11 @@ Creates a working xeplr application — an API, sign-in, and a UI — from a few
4
4
  questions, installs it, and sets up its databases.
5
5
 
6
6
  ```bash
7
- npx @xeplr/cli new myapp
7
+ npx @xeplr/cli@latest new myapp
8
8
  ```
9
9
 
10
+ `@latest` makes npx fetch the newest version rather than one it cached earlier.
11
+
10
12
  ## What you get
11
13
 
12
14
  ```
@@ -28,16 +30,23 @@ Already working, with nothing to wire up:
28
30
  table. Neither is written by hand: both are screens
29
31
  ([`@xeplr/ui-factory`](https://www.npmjs.com/package/@xeplr/ui-factory)),
30
32
  published when the API first starts.
31
- - **A Forms page** for Super Admin — every form in the app; make a new one by
32
- hand (no Claude needed), design its form and its list, publish (which creates
33
- or changes its table), open it. Nobody else sees it, and the API refuses
34
- everyone else.
33
+ - **Configure UI** for Super Admin, in the settings menu (top right) — not in
34
+ the side rail, which is for the pages people use:
35
+ - **Forms**: every UI in the app. New form (a **label** people see and a
36
+ **key** that names its table), design its form and its list, publish (which
37
+ creates or changes its table), open it, **add it to the side rail** — no
38
+ code, no Claude needed.
39
+ - **Menu**: rename, reorder and hide the side rail's items.
40
+
41
+ Nobody else sees it, and the API refuses everyone else.
35
42
  - **Multi-tenancy, if you ask for it** — companies (or companies and
36
43
  workspaces, up to four levels). Every row is stamped with the one it was made
37
44
  in, every read sees only its rows, membership is checked on every request,
38
45
  and choosing one is the first screen after signing in.
39
46
  - **A welcome screen** that checks it can reach everything and tells you which
40
47
  files to change first.
48
+ - **READMEs** at the project root and in `api/` and `ui/`: how to start it,
49
+ every command, where things live, and the rules the app follows.
41
50
  - **A `CLAUDE.md`** that tells Claude how to create a new UI in this app — the
42
51
  screens, the page with its front-end hooks, the server hooks and model, the
43
52
  route and menu entry — and a ready prompt (also shown beside the sample):
@@ -47,6 +56,21 @@ Already working, with nothing to wire up:
47
56
  > acres (number, at least 0), Started on (date), Notes (long text). Show Name,
48
57
  > Region and Area in the list. Follow "Create a new UI" in CLAUDE.md.
49
58
 
59
+ ## Rules the generated app follows
60
+
61
+ These are architecture decisions, not defaults to tune — each one exists because the alternative failed quietly.
62
+
63
+ | Rule | Where | Why |
64
+ |---|---|---|
65
+ | **Records live in real tables, one column per field — never JSON.** | `@xeplr/factory` | `select * from tasks` and plain-SQL reports must work. Only a screen's *design* is JSON (the `factory_screens` table). |
66
+ | **A key and a label, everywhere.** A form's key (`farming_department`) names its screens and table and never changes once published; its label is renamed any time. A menu item's key (`menus.name`, used by `drawerItems` / `settingsOverrides` in `ui/src/App.jsx` and `ui/src/menu.js`) is what code matches; its label is what the rail shows. | `@xeplr/auth`, `@xeplr/ui-account` | Code must never break because someone renamed something people read. No label is written in code. |
67
+ | **`REDIS_PREFIX` is required and unique per app** (`api/development.env`, set to `<name>:`). | `@xeplr/auth`, `@xeplr/utils` | Two apps on one Redis under the shared default serve each other's sessions, menus and API permissions. Sign-in refuses to start without it, or with `xeplr:`. |
68
+ | **Designing, new forms and publishing are Super Admin only.** | `api/routes/access.js`, `@xeplr/auth` menu routes | Publishing changes database tables. Every other screen route checks the permission catalog. |
69
+ | **The browser is not a security boundary.** Front-end hooks (`ui/src/pages/Edit<Form>.jsx`) shape what people see and send; anything that must hold goes in server hooks (`api/screens/<form>/<form>.hooks.js`); data shape in the model (`<form>.model.js`). | `@xeplr/ui-factory`, `@xeplr/factory` | |
70
+ | **Every data address is under `/api`.** | `api/routes`, `ui/vite.config.js` | A page path and a data path must never collide. |
71
+ | **No guessed database names or connections.** | `api/development.env` | A wrong-but-present value starts cleanly and reads as empty data. |
72
+ | **Email is checked at start, never fatal.** The sign-in banner shows `email ✓ …` or `✗ NOT WORKING — reason`. | `@xeplr/auth` | Sign-in works without email; activation, invite and reset links cannot be sent until `EMAIL_PROVIDER` is set. |
73
+
50
74
  ## Before you start
51
75
 
52
76
  - **Node.js** 18 or later
@@ -83,13 +107,49 @@ cd myapp/api && npm run start-api # your API — publishes the sample screens
83
107
  cd myapp/ui && npm run dev # the app
84
108
  ```
85
109
 
86
- Open the UI and sign in with the account you named.
110
+ Open the UI and sign in with the account you named. As Super Admin you will
111
+ see **Configure UI** in the settings menu, top right.
112
+
113
+ **Use a new project name for a new app.** The name decides the database names
114
+ (`<name>_auth`, `<name>_api`); an existing database is kept as it is, with its
115
+ accounts — the super admin you enter is created only in a fresh one.
87
116
 
88
117
  `xeplr new myapp --no-install` only writes the files; then run `npm install` in
89
118
  `api` and `ui`, and `npm run setup` in `api`, yourself. If set-up stops part
90
119
  way (Postgres not running, say), the installer says which step and the command
91
120
  to run again.
92
121
 
122
+ ## Creating a new UI
123
+
124
+ Two ways, both in the running app's project:
125
+
126
+ - **No code** — Configure UI → Forms → New form → design → Publish → Add to menu.
127
+ - **With Claude** — open Claude in the project folder and give it this (it is
128
+ also beside the sample, with a Copy button):
129
+
130
+ > Create a new UI for farming departments. One record is a farming department
131
+ > with: Name (required), Region (dropdown: North, South, East, West), Area in
132
+ > acres (number, at least 0), Started on (date), Notes (long text). Show Name,
133
+ > Region and Area in the list. Follow "Create a new UI" in CLAUDE.md.
134
+
135
+ Claude follows `CLAUDE.md`: the screens and server hooks and model
136
+ (`npx xeplr-factory screens … --no-pages`), the page with its front-end hooks,
137
+ the route, the side-rail item and its menu row. Then restart the sign-in
138
+ service and the API — the API publishes the new screens and creates the table.
139
+
140
+ ## Commands in a generated project
141
+
142
+ | Where | Command | Does |
143
+ |---|---|---|
144
+ | `api/` | `npm run setup` | create both databases, the sign-in tables, permissions and menus |
145
+ | `api/` | `npm run start-auth` | the sign-in service |
146
+ | `api/` | `npm run start-api` | the API — runs migrations and publishes never-published screens on start |
147
+ | `api/` | `npm run migrate:auth` | apply new `migrations-auth/*.sql` (e.g. a new menu row) |
148
+ | `api/` | `npm run db:encrypt` | redo the encrypted database connection |
149
+ | `api/` | `npx xeplr-factory screens screens/<form>/<form>.entity.json -o screens/<form> --no-pages` | a form's screens, server hooks and model from its spec |
150
+ | `api/` | `npx xeplr-factory validate <screen>.json` | check a screen document |
151
+ | `ui/` | `npm run dev` | the app |
152
+
93
153
  ## Changing the database connection later
94
154
 
95
155
  A password rotates, the database moves, or the first answer was wrong. From
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xeplr/cli",
3
- "version": "0.1.5",
3
+ "version": "0.1.7",
4
4
  "description": "Creates a working xeplr application — API, sign-in and UI — from a few answers.",
5
5
  "license": "MIT",
6
6
  "author": "xeppie <admin@xeplr.com>",
@@ -0,0 +1,48 @@
1
+ # __NAME__
2
+
3
+ An xeplr application, created by [`@xeplr/cli`](https://www.npmjs.com/package/@xeplr/cli).
4
+
5
+ ```
6
+ __NAME__/
7
+ ├─ api/ the API and the sign-in service → api/README.md
8
+ ├─ ui/ the React app → ui/README.md
9
+ └─ CLAUDE.md how to change this app — for Claude, and a good read for people
10
+ ```
11
+
12
+ ## Start it
13
+
14
+ Needs **PostgreSQL** and **Redis** running.
15
+
16
+ ```bash
17
+ cd api && npm run start-auth # sign-in http://localhost:__AUTH_PORT__
18
+ cd api && npm run start-api # the API http://localhost:__API_PORT__
19
+ cd ui && npm run dev # the app http://localhost:__UI_PORT__
20
+ ```
21
+
22
+ Open http://localhost:__UI_PORT__ and sign in as `__ADMIN_EMAIL__`.
23
+
24
+ ## What is in it
25
+
26
+ - **Sign-in** — login, register, password reset, profile, and the admin screens for users, roles and permissions (`@xeplr/auth`, `@xeplr/ui-account`).
27
+ - **Tasks** — a sample built from screens: a list, and a form it opens in a popup, saved into an ordinary `tasks` table.
28
+ - **Configure UI** — in the settings menu, for Super Admin: every form (make one, design it, publish it, add it to the side rail) and the side rail itself (rename, reorder, hide).
29
+
30
+ ## Create a new UI
31
+
32
+ - **Without code** — Configure UI → Forms → New form → design → Publish → Add to menu.
33
+ - **With Claude** — open Claude in this folder and give it (change the name and the fields):
34
+
35
+ > Create a new UI for farming departments. One record is a farming department with: Name (required), Region (dropdown: North, South, East, West), Area in acres (number, at least 0), Started on (date), Notes (long text). Show Name, Region and Area in the list. Follow "Create a new UI" in CLAUDE.md.
36
+
37
+ ## Rules this app follows
38
+
39
+ | Rule | Why |
40
+ |---|---|
41
+ | Records live in **real tables**, one column per field — never JSON. | Reports stay plain SQL. |
42
+ | A **key** and a **label**, everywhere: code uses keys (form keys, menu keys); people read labels, renamed in Configure UI. | Renaming what people see never breaks code. |
43
+ | **`REDIS_PREFIX`** in `api/development.env` is required and unique to this app. | Apps sharing a Redis would otherwise serve each other's sessions and permissions. |
44
+ | Designing and publishing forms is **Super Admin only**. | Publishing changes database tables. |
45
+ | Rules that must hold go in **server hooks**; the browser only shapes what people see and send. | The browser is not a security boundary. |
46
+ | Every data address is under **`/api`**. | A page and a data path must never collide. |
47
+
48
+ The full list, and where each piece lives, is in `CLAUDE.md`.
@@ -0,0 +1,40 @@
1
+ # __NAME__ — api
2
+
3
+ The API (`@xeplr/base-apis`) and the sign-in service (`@xeplr/auth`), with this app's forms served by `@xeplr/factory`.
4
+
5
+ ## Commands
6
+
7
+ | Command | Does |
8
+ |---|---|
9
+ | `npm run setup` | create both databases (`__NAME___auth`, `__NAME___api`), the sign-in tables, permissions and menus |
10
+ | `npm run start-auth` | the sign-in service, port __AUTH_PORT__ — refuses to start without Redis or `REDIS_PREFIX`; its banner says whether email works |
11
+ | `npm run start-api` | the API, port __API_PORT__ — runs `migrations/` and publishes never-published screens on start |
12
+ | `npm run migrate:auth` | apply new `migrations-auth/*.sql` (a new menu row, say), then restart sign-in |
13
+ | `npm run db:encrypt` | redo the encrypted database connection |
14
+ | `npm run check-env` | check every required setting is present |
15
+ | `npx xeplr-factory screens screens/<form>/<form>.entity.json -o screens/<form> --no-pages` | a form's screens, server hooks and model from its spec |
16
+ | `npx xeplr-factory validate <screen>.json` | check a screen document |
17
+
18
+ ## Layout
19
+
20
+ | Path | What |
21
+ |---|---|
22
+ | `development.env` | every setting — ports, the encrypted connection, `REDIS_PREFIX`, secrets, the super admin, email |
23
+ | `env.required.js` | the settings that must be present; the API refuses to start and names any that are missing |
24
+ | `app.js` | the Express app: the auth gate, and the routes |
25
+ | `routes/index.js` | this app's own routes — every data address under `/api` |
26
+ | `routes/access.js` | who may design and publish forms (Super Admin) |
27
+ | `screens/` | the forms this app ships with: per form, its spec, list and edit screens, server hooks and model — registered in `screens/index.js` |
28
+ | `migrations/` | hand-written SQL for tables no form owns |
29
+ | `migrations-auth/` | this app's rows in the sign-in database — menus (by key), permissions |
30
+ | `models/` | models for hand-written tables |
31
+
32
+ ## Settings to know
33
+
34
+ | Setting | |
35
+ |---|---|
36
+ | `REDIS_PREFIX` | **required, unique to this app** (`__NAME__:`) |
37
+ | `__PREFIX___CONNECTION`, `AUTH_DB_CONNECTION_INFO_ENCRYPTED` | the database, encrypted — `npm run db:encrypt` |
38
+ | `DB_API`, `AUTH_DB_NAME` | the two database names — never guessed |
39
+ | `AUTH_SUPER_ADMIN_EMAIL` / `_PASSWORD` | the first account — created once, when the sign-in database is first set up |
40
+ | `EMAIL_PROVIDER` and its settings | optional; without them sign-in works, but activation and reset links cannot be sent |
@@ -0,0 +1,28 @@
1
+ # __NAME__ — ui
2
+
3
+ The React app (Vite), using `@xeplr/ui-account` for sign-in and the app shell and `@xeplr/ui-factory` for forms.
4
+
5
+ ```bash
6
+ npm run dev # http://localhost:__UI_PORT__
7
+ npm run build # → dist/
8
+ ```
9
+
10
+ `.env` holds the port and where the sign-in service and the API are; `vite.config.js` proxies `/auth/api` to sign-in and `/api` (and `/health`, `/whoami`) to the API. A new data prefix must be added there too.
11
+
12
+ ## Layout
13
+
14
+ | Path | What |
15
+ |---|---|
16
+ | `src/main.jsx` | `ThemeProvider` (required — the theme's colours exist only inside it) and `AccessProvider` |
17
+ | `src/App.jsx` | routes, the side rail (`drawerItems`) and the settings menu (`settingsOverrides`) — **by key**, never by label |
18
+ | `src/menu.js` | every menu key this app uses; forms added to the menu are `form:<key>` |
19
+ | `src/api/factory.js` | the calls to the API's forms routes |
20
+ | `src/pages/Tasks.jsx` | the sample list; `EditTask.jsx` holds the task form's **front-end hooks** (`TaskHooks extends FactoryHooks` — every method calls `super`) |
21
+ | `src/pages/ConfigureUI.jsx` | Configure UI (Super Admin): `Forms.jsx` and `MenuSettings.jsx` tabs; `FormDesigner.jsx` designs one form |
22
+ | `src/pages/FormRecords.jsx` | opens any published form — what a form added to the menu links to |
23
+
24
+ ## Rules
25
+
26
+ - `authFetch` returns the **parsed body**, not a Response — no `.json()`.
27
+ - A side-rail item needs an **icon** (a collapsed rail shows icons only) and its key must exist as a menu row, or it is dropped silently.
28
+ - Set page backgrounds on a container inside the theme, never on `body`.