@forumone/create-throughline 1.0.1 → 1.0.2-next-0ecb757

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/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # @forumone/create-throughline
2
2
 
3
+ ## 1.0.2-next-0ecb757
4
+
5
+ ### Patch Changes
6
+
7
+ - 0ecb757: A scaffolded project puts its env file where `next dev` reads it, and does not make every account an administrator. The instructions copy `.env.example` to `apps/web/.env.local` rather than the root, which `next dev` in `apps/web` never read. New users default to `editor`; the first account, made at `/admin/create-first-user`, is the admin; and only an admin may set a role or a group.
8
+
3
9
  ## 1.0.1
4
10
 
5
11
  ## 1.0.0
@@ -1 +1 @@
1
- {"version":3,"file":"post-install.d.ts","sourceRoot":"","sources":["../src/post-install.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AAE3C;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CA6FrD"}
1
+ {"version":3,"file":"post-install.d.ts","sourceRoot":"","sources":["../src/post-install.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AAE3C;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CA+FrD"}
@@ -14,7 +14,10 @@ export function printNextSteps(answers) {
14
14
  if (!answers.installDeps) {
15
15
  lines.push(formatStep(step++, pc.bold('pnpm install')));
16
16
  }
17
- lines.push(formatStep(step++, `Copy ${pc.bold('.env.example')} to ${pc.bold('.env.local')} and fill in values`));
17
+ lines.push(formatStep(step++,
18
+ // apps/web, not the root: `next dev` reads env files from its own
19
+ // directory, and the Payload CLI looks there before walking up.
20
+ `Copy ${pc.bold('.env.example')} to ${pc.bold('apps/web/.env.local')} and fill in values`));
18
21
  if (answers.databasePlatform === 'neon') {
19
22
  lines.push(` ${pc.dim('- Create a Neon project; use its connection string for DATABASE_URI')}`);
20
23
  }
@@ -43,7 +46,7 @@ export function printNextSteps(answers) {
43
46
  lines.push(` ${pc.dim('pnpm --dir apps/web generate:importmap')}`);
44
47
  lines.push(formatStep(step++, `${pc.bold('pnpm dev')} to run locally`));
45
48
  lines.push(formatStep(step++, 'Open http://localhost:3000/admin and create your first admin user'));
46
- lines.push(formatStep(step++, 'In the admin, create one key under MCP → Payload MCP API Keys'));
49
+ lines.push(formatStep(step++, 'In the admin, create one key under MCP → API Keys'));
47
50
  lines.push(formatStep(step, 'Give that key to Claude (or your MCP client) for /api/mcp — see the generated README.md'));
48
51
  // eslint-disable-next-line no-console
49
52
  console.log();
@@ -1 +1 @@
1
- {"version":3,"file":"post-install.js","sourceRoot":"","sources":["../src/post-install.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"post-install.js","sourceRoot":"","sources":["../src/post-install.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAA;AACpC,OAAO,EAAE,MAAM,YAAY,CAAA;AAG3B;;;;;GAKG;AACH,MAAM,UAAU,cAAc,CAAC,OAAgB;IAC7C,MAAM,KAAK,GAAa,EAAE,CAAA;IAC1B,IAAI,IAAI,GAAG,CAAC,CAAA;IAEZ,MAAM,OAAO,GAAG,QAAQ,CAAC,OAAO,CAAC,SAAS,CAAC,CAAA;IAC3C,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,EAAE,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,OAAO,EAAE,CAAC,CAAC,CAAA;IAE7D,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC;QACzB,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,EAAE,EAAE,EAAE,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC,CAAA;IACzD,CAAC;IAED,KAAK,CAAC,IAAI,CACR,UAAU,CACR,IAAI,EAAE;IACN,kEAAkE;IAClE,gEAAgE;IAChE,QAAQ,EAAE,CAAC,IAAI,CAAC,cAAc,CAAC,OAAO,EAAE,CAAC,IAAI,CAAC,qBAAqB,CAAC,qBAAqB,CAC1F,CACF,CAAA;IAED,IAAI,OAAO,CAAC,gBAAgB,KAAK,MAAM,EAAE,CAAC;QACxC,KAAK,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC,GAAG,CAAC,qEAAqE,CAAC,EAAE,CAAC,CAAA;IACvG,CAAC;SAAM,IAAI,OAAO,CAAC,gBAAgB,KAAK,UAAU,EAAE,CAAC;QACnD,KAAK,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC,GAAG,CAAC,gFAAgF,CAAC,EAAE,CAAC,CAAA;IAClH,CAAC;SAAM,CAAC;QACN,KAAK,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC,GAAG,CAAC,+EAA+E,CAAC,EAAE,CAAC,CAAA;IACjH,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,EAAE,EAAE,4BAA4B,CAAC,CAAC,CAAA;IAC5D,KAAK,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC,GAAG,CAAC,2CAA2C,CAAC,EAAE,CAAC,CAAA;IAC3E,KAAK,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC,GAAG,CAAC,kDAAkD,CAAC,EAAE,CAAC,CAAA;IAElF,2EAA2E;IAC3E,2EAA2E;IAC3E,IAAI,OAAO,CAAC,cAAc,EAAE,CAAC;QAC3B,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,EAAE,EAAE,0DAA0D,CAAC,CAAC,CAAA;QAC1F,KAAK,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC,GAAG,CAAC,qCAAqC,CAAC,EAAE,CAAC,CAAA;IACvE,CAAC;IAED,yEAAyE;IACzE,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,EAAE,EAAE,uCAAuC,CAAC,CAAC,CAAA;IACvE,KAAK,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC,GAAG,CAAC,4CAA4C,CAAC,EAAE,CAAC,CAAA;IAC5E,KAAK,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC,GAAG,CAAC,6BAA6B,CAAC,EAAE,CAAC,CAAA;IAE7D,0EAA0E;IAC1E,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,EAAE,EAAE,6DAA6D,CAAC,CAAC,CAAA;IAC7F,KAAK,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC,GAAG,CAAC,oCAAoC,CAAC,EAAE,CAAC,CAAA;IACpE,KAAK,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC,GAAG,CAAC,wCAAwC,CAAC,EAAE,CAAC,CAAA;IAExE,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,EAAE,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,iBAAiB,CAAC,CAAC,CAAA;IACvE,KAAK,CAAC,IAAI,CACR,UAAU,CACR,IAAI,EAAE,EACN,mEAAmE,CACpE,CACF,CAAA;IACD,KAAK,CAAC,IAAI,CACR,UAAU,CAAC,IAAI,EAAE,EAAE,mDAAmD,CAAC,CACxE,CAAA;IACD,KAAK,CAAC,IAAI,CACR,UAAU,CACR,IAAI,EACJ,yFAAyF,CAC1F,CACF,CAAA;IAED,sCAAsC;IACtC,OAAO,CAAC,GAAG,EAAE,CAAA;IACb,sCAAsC;IACtC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAA;IACnC,sCAAsC;IACtC,OAAO,CAAC,GAAG,EAAE,CAAA;IACb,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,sCAAsC;QACtC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;IACnB,CAAC;IAED,sCAAsC;IACtC,OAAO,CAAC,GAAG,EAAE,CAAA;IACb,sCAAsC;IACtC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,8CAA8C,CAAC,CAAC,CAAA;IACnE,MAAM,cAAc,GAAG;QACrB,8DAA8D;QAC9D,qEAAqE;KACtE,CAAA;IACD,IAAI,CAAC,OAAO,CAAC,cAAc,EAAE,CAAC;QAC5B,cAAc,CAAC,IAAI,CAAC,2DAA2D,CAAC,CAAA;IAClF,CAAC;IACD,KAAK,MAAM,IAAI,IAAI,cAAc,EAAE,CAAC;QAClC,sCAAsC;QACtC,OAAO,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC,GAAG,CAAC,KAAK,IAAI,EAAE,CAAC,EAAE,CAAC,CAAA;IACzC,CAAC;IAED,sCAAsC;IACtC,OAAO,CAAC,GAAG,EAAE,CAAA;AACf,CAAC;AAED,SAAS,UAAU,CAAC,CAAS,EAAE,IAAY;IACzC,OAAO,GAAG,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,IAAI,EAAE,CAAA;AACxC,CAAC"}
@@ -19,12 +19,12 @@ This is a Throughline project: a Payload CMS application wired with the Throughl
19
19
  pnpm install
20
20
 
21
21
  # 2. Copy the env template
22
- cp .env.example .env.local
22
+ cp .env.example apps/web/.env.local # apps/web: `next dev` reads env files from there
23
23
 
24
24
  # 3. Generate secrets (run each three times for the three secret slots)
25
25
  openssl rand -base64 48
26
26
 
27
- # 4. Edit .env.local and fill in:
27
+ # 4. Edit apps/web/.env.local and fill in:
28
28
  # - DATABASE_URI — your Postgres connection string
29
29
  # - PAYLOAD_SECRET — generated above
30
30
  # - APPROVAL_TOKEN_SECRET — generated above
@@ -50,7 +50,8 @@ pnpm --dir apps/web generate:importmap
50
50
  # 7. Start the dev server
51
51
  pnpm dev
52
52
 
53
- # 8. Visit http://localhost:3000/admin and create your first user.
53
+ # 8. Visit http://localhost:3000/admin and create your first user. It is the admin;
54
+ # every account after it starts as an editor, and an admin grants more.
54
55
  ```
55
56
 
56
57
  ## After admin signup
@@ -140,25 +140,46 @@ const isAdmin: Access = ({ req: { user } }) =>
140
140
  Array.isArray(user.roles) &&
141
141
  (user.roles as unknown[]).includes('admin')
142
142
 
143
+ // Only an admin may set a role or a group, so nobody can grant themselves one.
144
+ const adminOnlyField = ({ req: { user } }: { req: { user?: unknown } }) =>
145
+ Array.isArray((user as { roles?: unknown } | undefined)?.roles) &&
146
+ ((user as { roles: unknown[] }).roles).includes('admin')
147
+
143
148
  // Users collection — extend with your own fields and SSO/auth provider.
144
149
  const Users: CollectionConfig = {
145
150
  slug: 'users',
146
151
  auth: true,
147
152
  admin: { useAsTitle: 'email' },
153
+ hooks: {
154
+ beforeChange: [
155
+ // The first account is the admin: /admin/create-first-user is how one
156
+ // exists at all. Every account after it starts as an editor, and an admin
157
+ // grants anything more.
158
+ async ({ data, operation, req }) => {
159
+ if (operation !== 'create') return data
160
+ const { totalDocs } = await req.payload.count({ collection: 'users', req })
161
+ return totalDocs === 0 ? { ...data, roles: ['admin'] } : data
162
+ },
163
+ ],
164
+ },
148
165
  fields: [
149
166
  { name: 'name', type: 'text' },
150
167
  {
151
168
  name: 'roles',
152
169
  type: 'select',
153
170
  hasMany: true,
154
- defaultValue: ['admin'],
171
+ // Least privilege: an editor authors content. The scaffold used to make
172
+ // every new account an administrator.
173
+ defaultValue: ['editor'],
155
174
  options: ['admin', 'editor', 'approver'],
175
+ access: { create: adminOnlyField, update: adminOnlyField },
156
176
  },
157
177
  {
158
178
  name: 'groups',
159
179
  type: 'select',
160
180
  hasMany: true,
161
181
  options: ['editorial', 'legal', 'communications', 'senior'],
182
+ access: { create: adminOnlyField, update: adminOnlyField },
162
183
  },
163
184
  ],
164
185
  }
@@ -1,4 +1,4 @@
1
1
  {
2
- "@forumone/throughline-design-system": "1.0.1",
3
- "@forumone/throughline": "1.0.1"
2
+ "@forumone/throughline-design-system": "1.0.2-next-0ecb757",
3
+ "@forumone/throughline": "1.0.2-next-0ecb757"
4
4
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@forumone/create-throughline",
3
- "version": "1.0.1",
3
+ "version": "1.0.2-next-0ecb757",
4
4
  "description": "Scaffolder for new Throughline projects (Payload CMS + MCP servers + Inngest workflows).",
5
5
  "type": "module",
6
6
  "bin": {
@@ -50,8 +50,8 @@
50
50
  "tsx": "^4.21.0",
51
51
  "typescript": "^5.6.0",
52
52
  "vitest": "^4.1.10",
53
- "@forumone/throughline-tsconfig": "0.0.1",
54
- "@forumone/throughline-eslint-config": "0.0.1"
53
+ "@forumone/throughline-eslint-config": "0.0.1",
54
+ "@forumone/throughline-tsconfig": "0.0.1"
55
55
  },
56
56
  "engines": {
57
57
  "node": ">=20.9.0"