create-freakpunch 0.1.0 → 0.2.0

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.
Files changed (79) hide show
  1. package/README.md +24 -23
  2. package/bin/create-freakpunch.mjs +6 -6
  3. package/files/README.md +19 -15
  4. package/files/app.config.ts +50 -58
  5. package/files/locales.ts +10 -0
  6. package/files/registry.ts +17 -0
  7. package/package.json +23 -23
  8. package/template/BACKEND.md +108 -86
  9. package/template/CLAUDE.md +15 -10
  10. package/template/design/COMPONENTS.md +1 -1
  11. package/template/design/DESIGN.md +3 -3
  12. package/template/design/PATTERNS.md +5 -5
  13. package/template/index.html +1 -1
  14. package/template/src/app.config.ts +50 -61
  15. package/template/src/app.roles.ts +24 -24
  16. package/template/src/core/api/demo.ts +8 -0
  17. package/template/src/core/audit/audit.service.ts +3 -34
  18. package/template/src/core/auth/auth.service.ts +25 -14
  19. package/template/src/core/auth/local-credentials.ts +46 -0
  20. package/template/src/core/auth/permissions.ts +1 -1
  21. package/template/src/core/company/company.service.ts +14 -12
  22. package/template/src/core/company/use-app-name.ts +7 -0
  23. package/template/src/core/components/page.tsx +4 -3
  24. package/template/src/core/config/runtime.ts +16 -14
  25. package/template/src/core/config/types.ts +3 -2
  26. package/template/src/core/layout/app-sidebar.tsx +19 -2
  27. package/template/src/core/notifications/notifications.service.ts +10 -115
  28. package/template/src/core/notifications/types.ts +5 -0
  29. package/template/src/core/setup/setup-gate.tsx +20 -0
  30. package/template/src/core/setup/setup.service.ts +101 -0
  31. package/template/src/core/users/users.service.ts +2 -2
  32. package/template/src/locales/en/auth.ts +2 -1
  33. package/template/src/locales/en/common.ts +1 -0
  34. package/template/src/locales/en/company.ts +3 -1
  35. package/template/src/locales/en/dashboard.ts +5 -0
  36. package/template/src/locales/en/setup.ts +45 -0
  37. package/template/src/locales/index.ts +4 -4
  38. package/template/src/locales/tr/auth.ts +2 -1
  39. package/template/src/locales/tr/common.ts +1 -0
  40. package/template/src/locales/tr/company.ts +3 -1
  41. package/template/src/locales/tr/dashboard.ts +5 -0
  42. package/template/src/locales/tr/setup.ts +49 -0
  43. package/template/src/modules/locales.ts +0 -4
  44. package/template/src/modules/registry.ts +17 -19
  45. package/template/src/pages/dashboard/dashboard-page.tsx +28 -243
  46. package/template/src/pages/dashboard/quick-actions.tsx +37 -0
  47. package/template/src/pages/login-page.tsx +26 -14
  48. package/template/src/pages/not-found-page.tsx +1 -2
  49. package/template/src/pages/settings/account/account.service.ts +22 -41
  50. package/template/src/pages/settings/account/notifications-page.tsx +3 -3
  51. package/template/src/pages/settings/company/general-page.tsx +6 -4
  52. package/template/src/pages/settings/company/integrations/integrations.service.ts +8 -28
  53. package/template/src/pages/settings/company/modules-page.tsx +10 -2
  54. package/template/src/pages/settings/company/roles-page.tsx +2 -1
  55. package/template/src/pages/setup-page.tsx +387 -0
  56. package/template/src/router.tsx +9 -4
  57. package/template/tools/new-module.mjs +90 -90
  58. package/template/tools/templates/module/index.ts.tpl +44 -37
  59. package/template/tools/templates/module/locales/en.ts.tpl +51 -45
  60. package/template/tools/templates/module/locales/tr.ts.tpl +55 -49
  61. package/template/{src/modules/products/pages/product-detail-page.tsx → tools/templates/module/pages/__id__-detail-page.tsx.tpl} +103 -108
  62. package/template/tools/templates/module/pages/__id__-form-page.tsx.tpl +121 -121
  63. package/template/tools/templates/module/pages/__id__-list-page.tsx.tpl +234 -237
  64. package/template/vite.config.ts +6 -3
  65. package/template/src/core/users/users.mock.ts +0 -24
  66. package/template/src/locales/en/landing.ts +0 -15
  67. package/template/src/locales/tr/landing.ts +0 -19
  68. package/template/src/modules/products/api/products.mock.ts +0 -46
  69. package/template/src/modules/products/api/products.service.ts +0 -84
  70. package/template/src/modules/products/components/product-status.tsx +0 -21
  71. package/template/src/modules/products/hooks.ts +0 -73
  72. package/template/src/modules/products/index.ts +0 -50
  73. package/template/src/modules/products/locales/en.ts +0 -78
  74. package/template/src/modules/products/locales/tr.ts +0 -82
  75. package/template/src/modules/products/pages/product-form-page.tsx +0 -211
  76. package/template/src/modules/products/pages/products-list-page.tsx +0 -286
  77. package/template/src/modules/products/types.ts +0 -61
  78. package/template/src/pages/dashboard/dashboard.service.ts +0 -92
  79. package/template/src/pages/landing-page.tsx +0 -79
package/README.md CHANGED
@@ -1,23 +1,24 @@
1
- # create-freakpunch
2
-
3
- Adds the freakpunch admin panel to any project as a self-contained `fp-admin/` folder. It has its own
4
- `package.json`, talks to your backend over HTTP, and works next to PHP, Laravel, Next.js or anything else.
5
-
6
- ```bash
7
- cd my-project
8
- npm create freakpunch@latest
9
- cd fp-admin
10
- npm run dev
11
- ```
12
-
13
- Options: `npm create freakpunch@latest my-folder`, `-- --no-install`, `-- --no-agent-files`.
14
-
15
- The command also adds a short pointer to `fp-admin/` in your project's `CLAUDE.md` and `AGENTS.md`
16
- (creating them if needed), so AI agents started at the project root follow the panel's design rules.
17
-
18
- Get newer freakpunch files later (your modules and config are never touched; `--dry-run` previews):
19
-
20
- ```bash
21
- cd fp-admin
22
- npm run fp:update
23
- ```
1
+ # create-freakpunch
2
+
3
+ Adds a clean admin panel to any project as a self-contained `fp-admin/` folder. It has its own
4
+ `package.json`, talks to your backend over HTTP, and works next to PHP, Laravel, Next.js or anything else.
5
+ The first time you open it, a setup wizard creates your company and admin account.
6
+
7
+ ```bash
8
+ cd my-project
9
+ npm create freakpunch@latest
10
+ cd fp-admin
11
+ npm run dev
12
+ ```
13
+
14
+ Options: `npm create freakpunch@latest my-folder`, `-- --no-install`, `-- --no-agent-files`.
15
+
16
+ The command also adds a short pointer to `fp-admin/` in your project's `CLAUDE.md` and `AGENTS.md`
17
+ (creating them if needed), so AI agents started at the project root follow the panel's design rules.
18
+
19
+ Get newer freakpunch files later (your modules and config are never touched; `--dry-run` previews):
20
+
21
+ ```bash
22
+ cd fp-admin
23
+ npm run fp:update
24
+ ```
@@ -23,6 +23,7 @@ const PROJECT_OWNED = [
23
23
  /^\.gitignore$/,
24
24
  /^package\.json$/,
25
25
  /^package-lock\.json$/,
26
+ /^\.env/,
26
27
  ]
27
28
  const isProjectOwned = (file) => PROJECT_OWNED.some((r) => r.test(file))
28
29
 
@@ -96,11 +97,10 @@ function create(args) {
96
97
  if (!isProjectOwned(target)) files[target] = hashFile(path.join(root, target))
97
98
  }
98
99
 
99
- // Installed defaults: start clean instead of with the template's demo content.
100
- const appName = path.basename(project).replace(/[^\w .-]/g, '') || 'Admin'
101
- const config = readFileSync(path.join(pkgDir, 'files/app.config.ts'), 'utf8').replaceAll('__APP_NAME__', appName)
102
- writeFileSync(path.join(root, 'src/app.config.ts'), config)
103
100
  copyFileSync(path.join(pkgDir, 'files/README.md'), path.join(root, 'README.md'))
101
+ // Browser data is per address, so each project gets its own dev port and panels never share accounts.
102
+ const port = 5200 + (parseInt(hash(root).slice(0, 6), 16) % 700)
103
+ writeFileSync(path.join(root, '.env.development'), `VITE_DEV_PORT=${port}\n`)
104
104
  writeManifest(root, files)
105
105
 
106
106
  const notes = flags.has('--no-agent-files') ? [] : addAgentNotes(project, dirName)
@@ -120,8 +120,8 @@ Done. Next:
120
120
  cd ${dirName}
121
121
  npm run dev
122
122
 
123
- Sign in with owner@freakpunch.site and any password (demo mode).
124
- Add a feature: npm run new-module -- assets --en "Assets" --tr "Zimmet"
123
+ The first time you open it, a setup wizard creates your company and admin account.
124
+ Add a feature: npm run new-module -- orders --en "Orders" --tr "Siparişler"
125
125
  Connect a backend, serve under /admin: see ${dirName}/BACKEND.md
126
126
  `)
127
127
  }
package/files/README.md CHANGED
@@ -1,15 +1,19 @@
1
- # Admin panel
2
-
3
- Built on [freakpunch](https://www.npmjs.com/package/create-freakpunch).
4
-
5
- ```bash
6
- npm run dev # start it
7
- npm run new-module -- assets --en "Assets" --tr "Zimmet" # add a feature
8
- npm run check # design rules + lint + build
9
- npm run fp:update # get newer freakpunch files
10
- ```
11
-
12
- - Your code: `src/modules/`, `src/app.config.ts`, `src/app.roles.ts`, `public/`.
13
- - freakpunch's code: everything else. `npm run fp:update` refreshes it, so don't edit it here.
14
- - Rules for people and AI agents: [CLAUDE.md](./CLAUDE.md) and [design/](./design).
15
- - Connecting a backend and deploying under `/admin`: [BACKEND.md](./BACKEND.md).
1
+ # Admin panel
2
+
3
+ Built on [freakpunch](https://www.npmjs.com/package/create-freakpunch).
4
+
5
+ ```bash
6
+ npm run dev # start it
7
+ npm run new-module -- orders --en "Orders" --tr "Siparişler" # add a feature
8
+ npm run check # design rules + lint + build
9
+ npm run fp:update # get newer freakpunch files
10
+ ```
11
+
12
+ The first time you open it, a setup wizard creates your company and admin account. To start over without a
13
+ backend, clear this site's data in your browser. Built-in pages such as Users and Audit log are off:
14
+ turn them on in `src/app.config.ts` → `features`.
15
+
16
+ - Your code: `src/modules/`, `src/app.config.ts`, `src/app.roles.ts`, `public/`.
17
+ - freakpunch's code: everything else. `npm run fp:update` refreshes it, so don't edit it here.
18
+ - Rules for people and AI agents: [CLAUDE.md](./CLAUDE.md) and [design/](./design).
19
+ - Connecting a backend and deploying under `/admin`: [BACKEND.md](./BACKEND.md).
@@ -1,58 +1,50 @@
1
- import type { AppConfig, AuthMode } from '@/core/config/types'
2
-
3
- /** This project's panel: name, brand, sidebar groups, modules and which built-in areas are on. */
4
- export const appConfig = {
5
- name: '__APP_NAME__',
6
- /** A preset key from src/core/theme/brand.ts, or a custom { color, foreground } pair. */
7
- brand: 'indigo',
8
-
9
- /** Workspaces shown in the sidebar switcher. */
10
- workspaces: [{ id: 'main', name: '__APP_NAME__', plan: 'common:plans.business' }],
11
-
12
- /** Sidebar group order; labels are translation keys. Modules attach nav items to these ids. */
13
- navGroups: [
14
- { id: 'overview', label: 'common:nav.groups.overview' },
15
- { id: 'catalog', label: 'common:nav.groups.catalog' },
16
- { id: 'content', label: 'common:nav.groups.content' },
17
- { id: 'system', label: 'common:nav.groups.system' },
18
- ],
19
-
20
- /**
21
- * Turn modules on/off. Keys must exist in src/modules/registry.ts. `products` is the
22
- * reference module agents copy patterns from; it stays off unless you want it.
23
- */
24
- modules: {
25
- products: false,
26
- // fp:modules
27
- },
28
-
29
- /** Marketing page at `/`; off, so `/` opens the panel. */
30
- landing: false,
31
-
32
- /** Built-in areas. Switch off what this project doesn't need. */
33
- features: {
34
- /** Off until connected: its demo feed talks about products and stock. */
35
- notifications: false,
36
- users: true,
37
- roles: true,
38
- securityPolicies: true,
39
- modules: true,
40
- integrations: true,
41
- auditLog: true,
42
- dangerZone: true,
43
- /** The sample KPI/revenue/activity cards on the dashboard. */
44
- demoDashboard: false,
45
- },
46
-
47
- /** Default ISO 4217 currency for formatting (Settings → Company → General can override it). */
48
- currency: 'USD',
49
-
50
- /** Real REST API base URL; mock services ignore it. */
51
- apiBaseUrl: import.meta.env.VITE_API_URL ?? '/api',
52
-
53
- /** mock (demo data) | bearer (JWT) | cookie (Laravel Sanctum). See BACKEND.md. */
54
- auth: {
55
- mode: (import.meta.env.VITE_AUTH_MODE ?? 'mock') as AuthMode,
56
- csrfUrl: import.meta.env.VITE_CSRF_URL ?? '/sanctum/csrf-cookie',
57
- },
58
- } satisfies AppConfig
1
+ import type { AppConfig, AuthMode } from '@/core/config/types'
2
+
3
+ /** This panel's settings. The company name and logo come from the setup wizard and Settings. */
4
+ export const appConfig = {
5
+ name: 'Admin',
6
+ /** A preset key from src/core/theme/brand.ts, or a custom { color, foreground } pair. */
7
+ brand: 'indigo',
8
+
9
+ workspaces: [{ id: 'main', name: 'Admin' }],
10
+
11
+ /** Sidebar group order; labels are translation keys. Modules attach nav items to these ids. */
12
+ navGroups: [
13
+ { id: 'overview', label: 'common:nav.groups.overview' },
14
+ { id: 'catalog', label: 'common:nav.groups.catalog' },
15
+ { id: 'content', label: 'common:nav.groups.content' },
16
+ { id: 'system', label: 'common:nav.groups.system' },
17
+ ],
18
+
19
+ /** Turn modules on/off. `npm run new-module` adds them here. */
20
+ modules: {
21
+ // fp:modules
22
+ },
23
+
24
+ /** No marketing page: `/` opens the panel. */
25
+ landing: false,
26
+
27
+ /** Built-in areas, off until a project needs them. Setting one to true adds its pages and menu items. */
28
+ features: {
29
+ notifications: false,
30
+ users: false,
31
+ roles: false,
32
+ securityPolicies: false,
33
+ modules: false,
34
+ integrations: false,
35
+ auditLog: false,
36
+ dangerZone: false,
37
+ },
38
+
39
+ /** Default ISO 4217 currency for the setup wizard. */
40
+ currency: 'USD',
41
+
42
+ /** Real REST API base URL. */
43
+ apiBaseUrl: import.meta.env.VITE_API_URL ?? '/api',
44
+
45
+ /** mock (no backend, data stays in this browser) | bearer (JWT) | cookie (Laravel Sanctum). See BACKEND.md. */
46
+ auth: {
47
+ mode: (import.meta.env.VITE_AUTH_MODE ?? 'mock') as AuthMode,
48
+ csrfUrl: import.meta.env.VITE_CSRF_URL ?? '/sanctum/csrf-cookie',
49
+ },
50
+ } satisfies AppConfig
@@ -0,0 +1,10 @@
1
+ // fp:locale-imports
2
+
3
+ /** Translations owned by modules; each key is the module's namespace. */
4
+ export const moduleLocalesEn = {
5
+ // fp:locale-en
6
+ }
7
+
8
+ export const moduleLocalesTr: typeof moduleLocalesEn = {
9
+ // fp:locale-tr
10
+ }
@@ -0,0 +1,17 @@
1
+ import { appConfig } from '@/app.config'
2
+ import type { AppModule } from '@/core/modules/types'
3
+ // fp:module-imports
4
+
5
+ /**
6
+ * Every module in this panel. `npm run new-module` registers new ones here and
7
+ * enables them in src/app.config.ts → `modules`.
8
+ */
9
+ export const moduleRegistry = {
10
+ // fp:module-registry
11
+ } satisfies Record<string, AppModule>
12
+
13
+ export type ModuleId = keyof typeof moduleRegistry
14
+
15
+ export const enabledModules: AppModule[] = (Object.keys(moduleRegistry) as ModuleId[])
16
+ .filter((id) => appConfig.modules[id])
17
+ .map((id) => moduleRegistry[id])
package/package.json CHANGED
@@ -1,23 +1,23 @@
1
- {
2
- "name": "create-freakpunch",
3
- "version": "0.1.0",
4
- "description": "Add the freakpunch admin panel to any project as an fp-admin folder.",
5
- "keywords": ["admin", "admin-panel", "dashboard", "react", "vite", "template"],
6
- "license": "UNLICENSED",
7
- "type": "module",
8
- "bin": {
9
- "create-freakpunch": "bin/create-freakpunch.mjs"
10
- },
11
- "files": [
12
- "bin",
13
- "files",
14
- "template"
15
- ],
16
- "engines": {
17
- "node": ">=20.11"
18
- },
19
- "scripts": {
20
- "build:template": "node scripts/build-template.mjs",
21
- "prepack": "node scripts/build-template.mjs"
22
- }
23
- }
1
+ {
2
+ "name": "create-freakpunch",
3
+ "version": "0.2.0",
4
+ "description": "Add the freakpunch admin panel to any project as an fp-admin folder.",
5
+ "keywords": ["admin", "admin-panel", "dashboard", "react", "vite", "template"],
6
+ "license": "UNLICENSED",
7
+ "type": "module",
8
+ "bin": {
9
+ "create-freakpunch": "bin/create-freakpunch.mjs"
10
+ },
11
+ "files": [
12
+ "bin",
13
+ "files",
14
+ "template"
15
+ ],
16
+ "engines": {
17
+ "node": ">=20.11"
18
+ },
19
+ "scripts": {
20
+ "build:template": "node scripts/build-template.mjs",
21
+ "prepack": "node scripts/build-template.mjs"
22
+ }
23
+ }
@@ -1,86 +1,108 @@
1
- # Connecting a backend
2
-
3
- The panel is a static single-page app. It talks to your backend over HTTP, so the backend can be
4
- Laravel, Next.js route handlers, Spring Boot or anything else. Until you switch it, everything runs on demo data.
5
-
6
- ## 1. Settings
7
-
8
- Put these in `.env` (build time, not secret: never put secrets in `VITE_` variables).
9
-
10
- | Variable | Example | Meaning |
11
- | --- | --- | --- |
12
- | `VITE_AUTH_MODE` | `bearer` or `cookie` | Default `mock` (demo data). `bearer`: token in the `Authorization` header. `cookie`: session cookie + `X-XSRF-TOKEN` (Laravel Sanctum). |
13
- | `VITE_API_URL` | `/api` or `https://api.example.com` | API base URL. |
14
- | `VITE_CSRF_URL` | `/sanctum/csrf-cookie` | Cookie mode: fetched before login. |
15
- | `VITE_BASE_PATH` | `/admin/` | Where the panel is served. Keep the trailing slash. Default `/`. |
16
- | `VITE_DEV_API_PROXY` | `http://localhost:8000` | `npm run dev` only: forwards `VITE_API_URL` calls to your backend. |
17
-
18
- ## 2. Auth endpoints
19
-
20
- ```
21
- POST {API}/auth/login { email, password } → { user, token?, expiresAt? }
22
- POST {API}/auth/logout
23
- ```
24
-
25
- - `token` is required in bearer mode and omitted in cookie mode. `expiresAt` is epoch milliseconds (default 7 days).
26
- - `user` matches `User` in `src/core/users/types.ts`. `role` must be a role the panel knows: `owner`, `admin`, `editor`, `viewer` or one from `src/app.roles.ts`.
27
- - Any `401` signs the user out. Errors may return `{ "message": "…" }`, which is shown to the user.
28
-
29
- **UI permission checks are not security.** Enforce every permission on the server, using the same strings (`assets.delete`).
30
-
31
- ## 3. Module endpoints
32
-
33
- Modules created with `npm run new-module` switch to these automatically when `VITE_AUTH_MODE` is not `mock`:
34
-
35
- ```
36
- GET {API}/assets?page=1&pageSize=10&search=x&sort=name.asc&status=active
37
- GET {API}/assets/:id
38
- POST {API}/assets
39
- PUT {API}/assets/:id
40
- DELETE {API}/assets/:id
41
- ```
42
-
43
- Pages are 1-based. List responses may use any of these shapes (`src/core/api/rest.ts`):
44
-
45
- ```jsonc
46
- { "items": [], "total": 0, "page": 1, "pageSize": 10 } // freakpunch
47
- { "data": [], "total": 0, "current_page": 1, "per_page": 10 } // Laravel paginate()
48
- { "data": [], "meta": { "total": 0, "current_page": 1, "per_page": 10 } } // Laravel API resource
49
- { "content": [], "totalElements": 0, "number": 0, "size": 10 } // Spring Data Page
50
- ```
51
-
52
- Spring Data expects a 0-based `page` in the request, and a backend may use other parameter names. For those,
53
- or for module-specific calls, write the method by hand in the module's `api/*.service.ts` using `http`.
54
-
55
- ## 4. Built-in areas that are still demo data
56
-
57
- These services run on mock data in every auth mode. For each one you use, implement its interface with
58
- `http` and change its one `export const xService = …` line. Switch off the rest in `src/app.config.ts`
59
- → `features` (their pages and menu items disappear). Don't leave a demo area visible on a real site.
60
-
61
- | Area | Service | Feature flag |
62
- | --- | --- | --- |
63
- | Users, profile | `src/core/users/users.service.ts` | `users` (Profile always shows) |
64
- | Company settings, branding, security policies | `src/core/company/company.service.ts` | `securityPolicies`, `dangerZone` (General and Branding always show) |
65
- | Audit log | `src/core/audit/audit.service.ts` | `auditLog` |
66
- | Notifications | `src/core/notifications/notifications.service.ts` | `notifications` |
67
- | Integrations, webhooks, API keys | `src/pages/settings/company/integrations/integrations.service.ts` | `integrations` |
68
- | Password, 2FA, sessions | `src/pages/settings/account/account.service.ts` | none |
69
-
70
- Updating a core service means editing a freakpunch file, which `npm run check` reports. Until there is a
71
- built-in way to replace them from a project, fix them in freakpunch itself so every project benefits.
72
-
73
- ## 5. Deploying
74
-
75
- `npm run build` writes static files to `dist/`. Any URL inside the panel must fall back to `index.html`.
76
-
77
- **Subdomain (`admin.example.com`):** deploy `dist/` anywhere static, or use the included `Dockerfile`.
78
-
79
- **Same domain (`example.com/admin`):** set `VITE_BASE_PATH=/admin/` and build, then:
80
-
81
- - *Laravel / PHP:* copy `dist/` to `public/admin/` and rewrite unknown `/admin/*` paths to `public/admin/index.html`.
82
- - *Next.js:* copy `dist/` to `public/admin/` and add a rewrite from `/admin/:path*` to `/admin/index.html`.
83
- - *nginx:* `location /admin/ { alias /var/www/admin/; try_files $uri $uri/ /admin/index.html; }`
84
-
85
- Same-domain hosting is the simplest route for cookie mode, because it avoids cross-site cookie and CORS setup.
86
- If the host project has its own `tsconfig.json`, add `fp-admin` to its `exclude`.
1
+ # Connecting a backend
2
+
3
+ The panel is a static single-page app. It talks to your backend over HTTP, so the backend can be
4
+ Laravel, Next.js route handlers, Spring Boot or anything else. Until you switch it, everything runs on demo data.
5
+
6
+ ## 1. Settings
7
+
8
+ Put these in `.env` (`.env.development` holds this panel's own dev port) (build time, not secret: never put secrets in `VITE_` variables).
9
+
10
+ | Variable | Example | Meaning |
11
+ | --- | --- | --- |
12
+ | `VITE_AUTH_MODE` | `bearer` or `cookie` | Default `mock` (demo data). `bearer`: token in the `Authorization` header. `cookie`: session cookie + `X-XSRF-TOKEN` (Laravel Sanctum). |
13
+ | `VITE_API_URL` | `/api` or `https://api.example.com` | API base URL. |
14
+ | `VITE_CSRF_URL` | `/sanctum/csrf-cookie` | Cookie mode: fetched before login. |
15
+ | `VITE_BASE_PATH` | `/admin/` | Where the panel is served. Keep the trailing slash. Default `/`. |
16
+ | `VITE_DEV_API_PROXY` | `http://localhost:8000` | `npm run dev` only: forwards `VITE_API_URL` calls to your backend. |
17
+
18
+ ## 2. Auth endpoints
19
+
20
+ ```
21
+ POST {API}/auth/login { email, password } → { user, token?, expiresAt? }
22
+ POST {API}/auth/logout
23
+ ```
24
+
25
+ - `token` is required in bearer mode and omitted in cookie mode. `expiresAt` is epoch milliseconds (default 7 days).
26
+ - `user` matches `User` in `src/core/users/types.ts`. `role` must be a role the panel knows: `owner`, `admin`, `editor`, `viewer` or one from `src/app.roles.ts`.
27
+ - Any `401` signs the user out. Errors may return `{ "message": "…" }`, which is shown to the user.
28
+
29
+ **UI permission checks are not security.** Enforce every permission on the server, using the same strings (`orders.delete`).
30
+
31
+ ## 3. First-run setup
32
+
33
+ Without a backend the setup wizard keeps the Owner account in this browser (salted hash, not real security),
34
+ so it is for building only. With a backend it uses:
35
+
36
+ ```
37
+ GET {API}/setup/status → { needsSetup: boolean }
38
+ POST {API}/setup → same response as /auth/login
39
+ ```
40
+
41
+ ```jsonc
42
+ {
43
+ "company": { "name": "", "language": "en", "timeZone": "Europe/Istanbul", "currency": "USD" },
44
+ "admin": { "firstName": "", "lastName": "", "email": "", "password": "" },
45
+ "branding": { "brand": "indigo", "logo": "data:image/png;base64,…" } // logo is optional
46
+ }
47
+ ```
48
+
49
+ **`POST /setup` must return 403 once an Owner exists**, or anyone could take over the panel. Check that, validate the
50
+ password and hash it on the server. If you create the first admin another way (seeder, CLI), skip these
51
+ endpoints: when `/setup/status` fails, the panel goes straight to login.
52
+
53
+ ## 4. Module endpoints
54
+
55
+ Modules created with `npm run new-module` switch to these automatically when `VITE_AUTH_MODE` is not `mock`:
56
+
57
+ ```
58
+ GET {API}/orders?page=1&pageSize=10&search=x&sort=name.asc&status=active
59
+ GET {API}/orders/:id
60
+ POST {API}/orders
61
+ PUT {API}/orders/:id
62
+ DELETE {API}/orders/:id
63
+ ```
64
+
65
+ Pages are 1-based. List responses may use any of these shapes (`src/core/api/rest.ts`):
66
+
67
+ ```jsonc
68
+ { "items": [], "total": 0, "page": 1, "pageSize": 10 } // freakpunch
69
+ { "data": [], "total": 0, "current_page": 1, "per_page": 10 } // Laravel paginate()
70
+ { "data": [], "meta": { "total": 0, "current_page": 1, "per_page": 10 } } // Laravel API resource
71
+ { "content": [], "totalElements": 0, "number": 0, "size": 10 } // Spring Data Page
72
+ ```
73
+
74
+ Spring Data expects a 0-based `page` in the request, and a backend may use other parameter names. For those,
75
+ or for module-specific calls, write the method by hand in the module's `api/*.service.ts` using `http`.
76
+
77
+ ## 5. Built-in areas that still save locally
78
+
79
+ These services keep their data in the browser in every auth mode, and they start empty. Most are switched off in a new panel. For each one you use, implement its interface with
80
+ `http` and change its one `export const xService = …` line. Switch off the rest in `src/app.config.ts`
81
+ → `features` (their pages and menu items disappear). Don't leave an unconnected area on for a real site.
82
+
83
+ | Area | Service | Feature flag |
84
+ | --- | --- | --- |
85
+ | Users, profile | `src/core/users/users.service.ts` | `users` (Profile always shows) |
86
+ | Company settings, branding, security policies | `src/core/company/company.service.ts` | `securityPolicies`, `dangerZone` (General and Branding always show) |
87
+ | Audit log | `src/core/audit/audit.service.ts` | `auditLog` |
88
+ | Notifications | `src/core/notifications/notifications.service.ts` | `notifications` |
89
+ | Integrations, webhooks, API keys | `src/pages/settings/company/integrations/integrations.service.ts` | `integrations` |
90
+ | Password, 2FA, sessions | `src/pages/settings/account/account.service.ts` | none |
91
+
92
+ Updating a core service means editing a freakpunch file, which `npm run check` reports. Until there is a
93
+ built-in way to replace them from a project, fix them in freakpunch itself so every project benefits.
94
+
95
+ ## 6. Deploying
96
+
97
+ `npm run build` writes static files to `dist/`. Any URL inside the panel must fall back to `index.html`.
98
+
99
+ **Subdomain (`admin.example.com`):** deploy `dist/` anywhere static, or use the included `Dockerfile`.
100
+
101
+ **Same domain (`example.com/admin`):** set `VITE_BASE_PATH=/admin/` and build, then:
102
+
103
+ - *Laravel / PHP:* copy `dist/` to `public/admin/` and rewrite unknown `/admin/*` paths to `public/admin/index.html`.
104
+ - *Next.js:* copy `dist/` to `public/admin/` and add a rewrite from `/admin/:path*` to `/admin/index.html`.
105
+ - *nginx:* `location /admin/ { alias /var/www/admin/; try_files $uri $uri/ /admin/index.html; }`
106
+
107
+ Same-domain hosting is the simplest route for cookie mode, because it avoids cross-site cookie and CORS setup.
108
+ If the host project has its own `tsconfig.json`, add `fp-admin` to its `exclude`.
@@ -5,20 +5,23 @@ New features are **modules** that look and behave exactly like the rest of the p
5
5
  look, layout or component style: reuse what exists and follow `design/`.
6
6
 
7
7
 
8
- Services return mock data until a backend is connected: see `BACKEND.md`.
8
+ A new panel is deliberately empty: no modules, no sample data, and optional built-in pages switched off in
9
+ `src/app.config.ts` → `features`. On first open, a setup wizard (`/setup`) creates the company and the Owner.
10
+ Until a backend is connected, data stays in the browser: see `BACKEND.md`.
9
11
 
10
12
  ## Rules for AI agents
11
13
 
12
14
  1. Read this file and `design/` before changing anything.
13
15
  2. New feature = new module: `npm run new-module -- <id> --en "Label" --tr "Etiket"`, then replace its sample
14
- fields. Use `src/modules/products` as the reference for detail pages and richer forms.
16
+ fields. The generated list, detail and form pages are the reference for new pages.
15
17
  3. **Only change project files:** `src/modules/**`, `src/app.config.ts`, `src/app.roles.ts`, `public/**`.
16
18
  Everything else (`src/core`, `src/pages`, `src/components/ui`, `src/locales`, `src/index.css`, `design/`,
17
19
  `tools/`) belongs to freakpunch and is replaced by updates. If something is missing there, say so to the user
18
20
  instead of editing or copying it.
19
21
  4. Every string in both EN and TR. Tokens only. Shared components first (`design/COMPONENTS.md`).
20
22
  5. Gate every route and action with a permission; add project-specific ones in `src/app.roles.ts`.
21
- 6. `npm run check` must pass before you finish.
23
+ 6. Never add sample or placeholder data to a panel unless the user asks for it.
24
+ 7. `npm run check` must pass before you finish.
22
25
 
23
26
  ## Commands
24
27
 
@@ -27,7 +30,7 @@ npm run dev # Vite dev server
27
30
  npm run build # tsc -b && vite build (must pass with no errors)
28
31
  npm run lint # oxlint (must pass with no errors or warnings)
29
32
  npm run check # design rules + lint + build: run this before finishing any change
30
- npm run new-module -- assets --en "Assets" --tr "Zimmet" [--group content]
33
+ npm run new-module -- orders --en "Orders" --tr "Siparişler" [--group content]
31
34
  npm run fp:update # installed copies: refresh freakpunch's files (add -- --dry-run to preview)
32
35
  docker build -t freakpunch . && docker run --rm -p 8080:80 freakpunch
33
36
  ```
@@ -71,6 +74,7 @@ src/
71
74
  require-auth (→ /login?redirect=…), roles, permissions (role → permission map),
72
75
  can (Can, useCan, usePermissions), require-permission (route guard), dev-role-switcher
73
76
  users/ user model, mock team (one demo user per role), users.service, hooks
77
+ setup/ first-run wizard service (local or POST /setup) + SetupGate
74
78
  company/ company settings (general, branding, security policies), password-policy, hooks
75
79
  audit/ audit.service (record + list), hooks
76
80
  notifications/ event catalog + types, notifications.service (feed + settings, mock, per user),
@@ -90,14 +94,15 @@ src/
90
94
  lib/ storage (namespaced localStorage), format (createFormatters, initials), phone, csv
91
95
  modules/
92
96
  registry.ts ← every available module; app.config.ts decides which are on
93
- products/ ← example module (copy this to start a new one)
97
+ locales.ts ← registers each module's translations
98
+ orders/ ← what `npm run new-module` generates
94
99
  index.ts module definition: nav, routes, quick actions (labels = i18n keys, permissions)
95
100
  locales/ en.ts + tr.ts (namespace = module id)
96
101
  types.ts entity types + Zod form schema
97
- api/ products.service.ts (interface + mock impl), products.mock.ts (seed)
102
+ api/ orders.service.ts (interface + mock impl), orders.mock.ts (seed)
98
103
  hooks.ts TanStack Query keys + hooks
99
104
  components/ pages/
100
- pages/ core pages: landing, login, dashboard/, not-found, no-access
105
+ pages/ core pages: setup, login, dashboard/, not-found, no-access
101
106
  settings/ settings-routes, settings-nav, settings-layout (left sub-nav),
102
107
  account/ (profile, security, notifications, preferences),
103
108
  company/ (general, branding, users, roles, security policies, modules,
@@ -169,7 +174,7 @@ Four built-in roles (`core/auth/roles.ts`), plus project-defined ones from `src/
169
174
  demoted, only transfer ownership), **admin** (everything except the danger zone; can't edit the Owner),
170
175
  **editor** (create/edit/delete in modules, no company settings), **viewer** (read-only).
171
176
  - `core/auth/permissions.ts` is the single role → permission map. Permission strings are
172
- `<resource>.<action>` (`products.delete`, `settings.company.edit`, `users.manage`,
177
+ `<resource>.<action>` (`orders.delete`, `settings.company.edit`, `users.manage`,
173
178
  `company.transfer`) and are meant to be reused 1:1 as Spring Security authorities. Every registered
174
179
  module automatically gets `<id>.view|create|edit|delete`.
175
180
  - UI: `useCan('x')` / `usePermissions().can` / `<Can permission="x">` (hide, or render-prop to
@@ -178,7 +183,7 @@ demoted, only transfer ownership), **admin** (everything except the danger zone;
178
183
  Owner rules for user management: `canManageUser(actor, target)`.
179
184
  - **UI checks are not security.** The backend must enforce every permission (the mock services
180
185
  enforce the Owner rules the same way a backend should).
181
- - Demo users (any password): owner@, admin@, editor@, viewer@freakpunch.site. In `npm run dev` the top
186
+ - In `npm run dev` the top
182
187
  bar has a role switcher (`DevRoleSwitcher`, code-split behind `import.meta.env.DEV`, absent from
183
188
  production builds).
184
189
 
@@ -207,7 +212,7 @@ components**: page titles, labels, `aria-label`, `placeholder`, toasts, empty st
207
212
  (modules: `locales/` and `src/modules/locales.ts`), use `useTranslation(['<ns>', 'common'])` and `t('common:actions.save')`
208
213
  for shared strings.
209
214
  - Config-like data (nav labels, crumbs, quick actions, nav groups, workspace plans) stores
210
- `I18nKey` values (`'products:nav'`) and is translated with `useAnyT()`.
215
+ `I18nKey` values (`'orders:nav'`) and is translated with `useAnyT()`.
211
216
  - Zod messages are keys: `vmsg('validation.minChars', { min: 2 })`; render errors with
212
217
  `FormFieldError` (translates at render time).
213
218
  - Formatting: `const fmt = useFormat()` → `fmt.currency/number/date/dateTime/relative/…` (Intl with the
@@ -90,7 +90,7 @@ Add more with `npx shadcn@latest add @sortui/<name> -y`, then rewrite the `cn` i
90
90
  ### Feedback
91
91
 
92
92
  - **`useConfirm()`** (`core/components/confirm-dialog.tsx`): promise-based confirm.
93
- `destructive: true` for irreversible actions, `typeToConfirm: 'acme'` to require typing a value
93
+ `destructive: true` for irreversible actions, `typeToConfirm: companyName` to require typing a value
94
94
  (danger zone).
95
95
  - **`toast`** from `sonner`: success after a save, error with the message on failure,
96
96
  `toast.promise` for row actions. Messages are translated.