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.
- package/README.md +24 -23
- package/bin/create-freakpunch.mjs +6 -6
- package/files/README.md +19 -15
- package/files/app.config.ts +50 -58
- package/files/locales.ts +10 -0
- package/files/registry.ts +17 -0
- package/package.json +23 -23
- package/template/BACKEND.md +108 -86
- package/template/CLAUDE.md +15 -10
- package/template/design/COMPONENTS.md +1 -1
- package/template/design/DESIGN.md +3 -3
- package/template/design/PATTERNS.md +5 -5
- package/template/index.html +1 -1
- package/template/src/app.config.ts +50 -61
- package/template/src/app.roles.ts +24 -24
- package/template/src/core/api/demo.ts +8 -0
- package/template/src/core/audit/audit.service.ts +3 -34
- package/template/src/core/auth/auth.service.ts +25 -14
- package/template/src/core/auth/local-credentials.ts +46 -0
- package/template/src/core/auth/permissions.ts +1 -1
- package/template/src/core/company/company.service.ts +14 -12
- package/template/src/core/company/use-app-name.ts +7 -0
- package/template/src/core/components/page.tsx +4 -3
- package/template/src/core/config/runtime.ts +16 -14
- package/template/src/core/config/types.ts +3 -2
- package/template/src/core/layout/app-sidebar.tsx +19 -2
- package/template/src/core/notifications/notifications.service.ts +10 -115
- package/template/src/core/notifications/types.ts +5 -0
- package/template/src/core/setup/setup-gate.tsx +20 -0
- package/template/src/core/setup/setup.service.ts +101 -0
- package/template/src/core/users/users.service.ts +2 -2
- package/template/src/locales/en/auth.ts +2 -1
- package/template/src/locales/en/common.ts +1 -0
- package/template/src/locales/en/company.ts +3 -1
- package/template/src/locales/en/dashboard.ts +5 -0
- package/template/src/locales/en/setup.ts +45 -0
- package/template/src/locales/index.ts +4 -4
- package/template/src/locales/tr/auth.ts +2 -1
- package/template/src/locales/tr/common.ts +1 -0
- package/template/src/locales/tr/company.ts +3 -1
- package/template/src/locales/tr/dashboard.ts +5 -0
- package/template/src/locales/tr/setup.ts +49 -0
- package/template/src/modules/locales.ts +0 -4
- package/template/src/modules/registry.ts +17 -19
- package/template/src/pages/dashboard/dashboard-page.tsx +28 -243
- package/template/src/pages/dashboard/quick-actions.tsx +37 -0
- package/template/src/pages/login-page.tsx +26 -14
- package/template/src/pages/not-found-page.tsx +1 -2
- package/template/src/pages/settings/account/account.service.ts +22 -41
- package/template/src/pages/settings/account/notifications-page.tsx +3 -3
- package/template/src/pages/settings/company/general-page.tsx +6 -4
- package/template/src/pages/settings/company/integrations/integrations.service.ts +8 -28
- package/template/src/pages/settings/company/modules-page.tsx +10 -2
- package/template/src/pages/settings/company/roles-page.tsx +2 -1
- package/template/src/pages/setup-page.tsx +387 -0
- package/template/src/router.tsx +9 -4
- package/template/tools/new-module.mjs +90 -90
- package/template/tools/templates/module/index.ts.tpl +44 -37
- package/template/tools/templates/module/locales/en.ts.tpl +51 -45
- package/template/tools/templates/module/locales/tr.ts.tpl +55 -49
- package/template/{src/modules/products/pages/product-detail-page.tsx → tools/templates/module/pages/__id__-detail-page.tsx.tpl} +103 -108
- package/template/tools/templates/module/pages/__id__-form-page.tsx.tpl +121 -121
- package/template/tools/templates/module/pages/__id__-list-page.tsx.tpl +234 -237
- package/template/vite.config.ts +6 -3
- package/template/src/core/users/users.mock.ts +0 -24
- package/template/src/locales/en/landing.ts +0 -15
- package/template/src/locales/tr/landing.ts +0 -19
- package/template/src/modules/products/api/products.mock.ts +0 -46
- package/template/src/modules/products/api/products.service.ts +0 -84
- package/template/src/modules/products/components/product-status.tsx +0 -21
- package/template/src/modules/products/hooks.ts +0 -73
- package/template/src/modules/products/index.ts +0 -50
- package/template/src/modules/products/locales/en.ts +0 -78
- package/template/src/modules/products/locales/tr.ts +0 -82
- package/template/src/modules/products/pages/product-form-page.tsx +0 -211
- package/template/src/modules/products/pages/products-list-page.tsx +0 -286
- package/template/src/modules/products/types.ts +0 -61
- package/template/src/pages/dashboard/dashboard.service.ts +0 -92
- package/template/src/pages/landing-page.tsx +0 -79
package/README.md
CHANGED
|
@@ -1,23 +1,24 @@
|
|
|
1
|
-
# create-freakpunch
|
|
2
|
-
|
|
3
|
-
Adds
|
|
4
|
-
`package.json`, talks to your backend over HTTP, and works next to PHP, Laravel, Next.js or anything else.
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
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
|
-
|
|
124
|
-
Add a feature: npm run new-module --
|
|
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 --
|
|
8
|
-
npm run check # design rules + lint + build
|
|
9
|
-
npm run fp:update # get newer freakpunch files
|
|
10
|
-
```
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
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).
|
package/files/app.config.ts
CHANGED
|
@@ -1,58 +1,50 @@
|
|
|
1
|
-
import type { AppConfig, AuthMode } from '@/core/config/types'
|
|
2
|
-
|
|
3
|
-
/** This
|
|
4
|
-
export const appConfig = {
|
|
5
|
-
name: '
|
|
6
|
-
/** A preset key from src/core/theme/brand.ts, or a custom { color, foreground } pair. */
|
|
7
|
-
brand: 'indigo',
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
{ id: '
|
|
15
|
-
{ id: '
|
|
16
|
-
{ id: '
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
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
|
package/files/locales.ts
ADDED
|
@@ -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.
|
|
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
|
+
}
|
package/template/BACKEND.md
CHANGED
|
@@ -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 (`
|
|
30
|
-
|
|
31
|
-
## 3.
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
GET
|
|
38
|
-
POST
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
```
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
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`.
|
package/template/CLAUDE.md
CHANGED
|
@@ -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
|
-
|
|
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.
|
|
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.
|
|
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 --
|
|
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
|
-
|
|
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/
|
|
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:
|
|
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>` (`
|
|
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
|
-
-
|
|
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 (`'
|
|
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:
|
|
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.
|