@kevinmarrec/create-app 0.8.0 → 0.10.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 +4 -0
- package/dist/index.js +1 -1
- package/package.json +14 -16
- package/template/.docker/traefik/bin/install_cert +18 -0
- package/template/.docker/traefik/bin/uninstall_cert +9 -0
- package/template/.docker/traefik/dynamic/tls.yml +4 -0
- package/template/.github/scripts/build-stats.md.ts +71 -0
- package/template/.github/workflows/ci.yml +16 -0
- package/template/.gitignore +2 -0
- package/template/.npmrc +0 -1
- package/template/.vscode/settings.json +1 -1
- package/template/README.md +330 -0
- package/template/api/.env.development +4 -0
- package/template/{server → api}/package.json +8 -7
- package/template/{server → api}/src/auth/index.ts +4 -1
- package/template/{server → api}/src/database/drizzle/config.ts +3 -2
- package/template/{server → api}/src/database/index.ts +6 -4
- package/template/api/src/env.ts +67 -0
- package/template/api/src/main.ts +39 -0
- package/template/{server → api}/src/orpc/context.ts +4 -3
- package/template/api/src/orpc/index.ts +27 -0
- package/template/{server → api}/src/orpc/middlewares/auth.ts +2 -1
- package/template/api/src/orpc/plugins/error.ts +17 -0
- package/template/{server → api}/src/orpc/router/index.ts +13 -1
- package/template/{server → api}/src/utils/cors.ts +8 -5
- package/template/{server → api}/src/utils/logger.ts +3 -1
- package/template/app/.env +1 -0
- package/template/{client → app}/index.html +1 -0
- package/template/{client → app}/package.json +9 -10
- package/template/{client → app}/src/App.vue +2 -1
- package/template/{client → app}/src/composables/content.ts +2 -1
- package/template/{client → app}/src/lib/orpc.ts +3 -1
- package/template/{client → app}/src/main.ts +1 -1
- package/template/{client → app}/vite.config.ts +1 -1
- package/template/compose.yaml +120 -12
- package/template/knip.config.ts +8 -10
- package/template/package.json +12 -11
- package/template/tsconfig.json +2 -2
- package/template/.scripts/dev.ts +0 -8
- package/template/client/.env +0 -1
- package/template/server/.env.development +0 -4
- package/template/server/src/env.d.ts +0 -11
- package/template/server/src/main.ts +0 -51
- package/template/server/src/orpc/handler.ts +0 -34
- package/template/server/src/orpc/index.ts +0 -18
- package/template/server/src/orpc/middlewares/index.ts +0 -1
- /package/template/{server → api}/src/database/migrations/0000_init.sql +0 -0
- /package/template/{server → api}/src/database/migrations/meta/0000_snapshot.json +0 -0
- /package/template/{server → api}/src/database/migrations/meta/_journal.json +0 -0
- /package/template/{server → api}/src/database/schema/accounts.ts +0 -0
- /package/template/{server → api}/src/database/schema/index.ts +0 -0
- /package/template/{server → api}/src/database/schema/sessions.ts +0 -0
- /package/template/{server → api}/src/database/schema/users.ts +0 -0
- /package/template/{server → api}/src/database/schema/verifications.ts +0 -0
- /package/template/{server → api}/tsconfig.json +0 -0
- /package/template/{client → app}/public/favicon.svg +0 -0
- /package/template/{client → app}/public/robots.txt +0 -0
- /package/template/{client → app}/src/components/.gitkeep +0 -0
- /package/template/{client → app}/src/composables/auth.ts +0 -0
- /package/template/{client → app}/src/composables/index.ts +0 -0
- /package/template/{client → app}/src/env.d.ts +0 -0
- /package/template/{client → app}/src/locales/en.yml +0 -0
- /package/template/{client → app}/src/locales/fr.yml +0 -0
- /package/template/{client → app}/tsconfig.json +0 -0
- /package/template/{client → app}/uno.config.ts +0 -0
- /package/template/{client → app}/wrangler.json +0 -0
package/README.md
CHANGED
|
@@ -16,4 +16,8 @@ CLI that scaffolds an opinionated [Bun](https://bun.sh) & [Vue](https://vuejs.or
|
|
|
16
16
|
|
|
17
17
|
```sh
|
|
18
18
|
bun create @kevinmarrec/app
|
|
19
|
+
# OR
|
|
20
|
+
bunx @kevinmarrec/create-app
|
|
19
21
|
```
|
|
22
|
+
|
|
23
|
+
After scaffolding, see the generated `README.md` in your project root for detailed setup instructions, including environment configuration, Docker setup, and development workflows.
|
package/dist/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kevinmarrec/create-app",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.
|
|
5
|
-
"packageManager": "bun@1.3.
|
|
4
|
+
"version": "0.10.0",
|
|
5
|
+
"packageManager": "bun@1.3.2",
|
|
6
6
|
"description": "CLI that scaffolds an opinionated Bun & Vue fullstack application.",
|
|
7
7
|
"author": "Kevin Marrec <kevin@marrec.io>",
|
|
8
8
|
"license": "MIT",
|
|
@@ -18,8 +18,8 @@
|
|
|
18
18
|
],
|
|
19
19
|
"workspaces": [
|
|
20
20
|
"template",
|
|
21
|
-
"template/
|
|
22
|
-
"template/
|
|
21
|
+
"template/api",
|
|
22
|
+
"template/app"
|
|
23
23
|
],
|
|
24
24
|
"bin": {
|
|
25
25
|
"create-app": "dist/index.js"
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
"check:unused": "knip -n",
|
|
40
40
|
"lint": "bun run check:eslint && bun run check:stylelint",
|
|
41
41
|
"lint:inspect": "bunx @eslint/config-inspector",
|
|
42
|
-
"playground": "bun
|
|
42
|
+
"playground": "bun run scripts/transform-compose.ts | docker compose -f -",
|
|
43
43
|
"release": "bumpp",
|
|
44
44
|
"update": "bunx taze -I -rwi",
|
|
45
45
|
"test": "vitest",
|
|
@@ -53,20 +53,18 @@
|
|
|
53
53
|
},
|
|
54
54
|
"devDependencies": {
|
|
55
55
|
"@faker-js/faker": "^10.1.0",
|
|
56
|
-
"@kevinmarrec/eslint-config": "^1.5.
|
|
57
|
-
"@kevinmarrec/stylelint-config": "^1.5.
|
|
58
|
-
"@kevinmarrec/tsconfig": "^1.5.
|
|
59
|
-
"@types/bun": "^1.3.
|
|
60
|
-
"@vitest/coverage-v8": "^4.0.
|
|
56
|
+
"@kevinmarrec/eslint-config": "^1.5.6",
|
|
57
|
+
"@kevinmarrec/stylelint-config": "^1.5.6",
|
|
58
|
+
"@kevinmarrec/tsconfig": "^1.5.6",
|
|
59
|
+
"@types/bun": "^1.3.2",
|
|
60
|
+
"@vitest/coverage-v8": "^4.0.9",
|
|
61
61
|
"bumpp": "^10.3.1",
|
|
62
62
|
"eslint": "^9.39.1",
|
|
63
|
-
"
|
|
64
|
-
"knip": "^5.67.1",
|
|
63
|
+
"knip": "^5.69.1",
|
|
65
64
|
"stylelint": "^16.25.0",
|
|
66
|
-
"
|
|
67
|
-
"tsdown": "^0.16.0",
|
|
65
|
+
"tsdown": "^0.16.4",
|
|
68
66
|
"typescript": "^5.9.3",
|
|
69
|
-
"vitest": "^4.0.
|
|
70
|
-
"vue-tsc": "^3.1.
|
|
67
|
+
"vitest": "^4.0.9",
|
|
68
|
+
"vue-tsc": "^3.1.4"
|
|
71
69
|
}
|
|
72
70
|
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
|
|
3
|
+
set -e
|
|
4
|
+
|
|
5
|
+
CERTS_DIR="$(cd "$(dirname "$0")/../certs" && pwd)"
|
|
6
|
+
|
|
7
|
+
if ! command -v mkcert >/dev/null 2>&1; then
|
|
8
|
+
echo "Error: mkcert is not installed." >&2
|
|
9
|
+
echo "Please install mkcert before running this script." >&2
|
|
10
|
+
echo "See https://github.com/FiloSottile/mkcert#installation for installation instructions." >&2
|
|
11
|
+
exit 1
|
|
12
|
+
fi
|
|
13
|
+
|
|
14
|
+
mkdir -p "$CERTS_DIR"
|
|
15
|
+
|
|
16
|
+
mkcert -install 2> /dev/null
|
|
17
|
+
|
|
18
|
+
mkcert -cert-file "$CERTS_DIR/dev.localhost.crt" -key-file "$CERTS_DIR/dev.localhost.key" "dev.localhost" "*.dev.localhost"
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import * as fs from 'node:fs'
|
|
2
|
+
import path from 'node:path'
|
|
3
|
+
import process from 'node:process'
|
|
4
|
+
import { parseArgs } from 'node:util'
|
|
5
|
+
|
|
6
|
+
import { filesize } from 'filesize'
|
|
7
|
+
import { x } from 'tinyexec'
|
|
8
|
+
import { glob } from 'tinyglobby'
|
|
9
|
+
|
|
10
|
+
interface FileStats {
|
|
11
|
+
file: string
|
|
12
|
+
size: number
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
async function getFileStats(directory: string) {
|
|
16
|
+
const fileStats: FileStats[] = []
|
|
17
|
+
|
|
18
|
+
for (const file of await glob(['**/*'], { cwd: directory })) {
|
|
19
|
+
const size = fs.statSync(path.join(directory, file)).size
|
|
20
|
+
fileStats.push({
|
|
21
|
+
file,
|
|
22
|
+
size,
|
|
23
|
+
})
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
fileStats.sort((a, b) => {
|
|
27
|
+
// Sort so that files starting with 'assets/' come first
|
|
28
|
+
if (a.file.startsWith('assets/') && !b.file.startsWith('assets/')) return -1
|
|
29
|
+
if (!a.file.startsWith('assets/') && b.file.startsWith('assets/')) return 1
|
|
30
|
+
|
|
31
|
+
// Within that, files ending with '.js' come first
|
|
32
|
+
if (a.file.endsWith('.js') && !b.file.endsWith('.js')) return -1
|
|
33
|
+
if (!a.file.endsWith('.js') && b.file.endsWith('.js')) return 1
|
|
34
|
+
|
|
35
|
+
// Otherwise sort alphabetically
|
|
36
|
+
return a.file.localeCompare(b.file)
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
return fileStats
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
async function generateFileStatsMarkdown(directory: string) {
|
|
43
|
+
const fileStats = await getFileStats(directory)
|
|
44
|
+
return [
|
|
45
|
+
'| File | Size |',
|
|
46
|
+
'| :--- | ---: |',
|
|
47
|
+
...fileStats.map(file => `| ${file.file} | ${filesize(file.size)} |`),
|
|
48
|
+
].join('\n')
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
async function main() {
|
|
52
|
+
const { positionals: [directory] } = parseArgs({
|
|
53
|
+
args: process.argv.slice(2),
|
|
54
|
+
allowPositionals: true,
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
if (!directory) {
|
|
58
|
+
process.stdout.write('Usage: analyze <directory>\n')
|
|
59
|
+
process.exit(1)
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
await x('bun', ['run', 'build'], { nodeOptions: { cwd: directory } })
|
|
63
|
+
|
|
64
|
+
const markdownTable = await generateFileStatsMarkdown(path.join(directory, 'dist'))
|
|
65
|
+
process.stdout.write(`${markdownTable}\n`)
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
main().catch((error) => {
|
|
69
|
+
console.error(error)
|
|
70
|
+
process.exit(1)
|
|
71
|
+
})
|
|
@@ -24,3 +24,19 @@ jobs:
|
|
|
24
24
|
|
|
25
25
|
- name: Type check
|
|
26
26
|
run: bun run check:types
|
|
27
|
+
project-size:
|
|
28
|
+
name: Analyze project build size
|
|
29
|
+
runs-on: ubuntu-latest
|
|
30
|
+
steps:
|
|
31
|
+
- name: Setup Bun
|
|
32
|
+
uses: kevinmarrec/workflows/setup-bun@v1
|
|
33
|
+
|
|
34
|
+
- name: Check api build size
|
|
35
|
+
run: |
|
|
36
|
+
echo "## API" >> $GITHUB_STEP_SUMMARY
|
|
37
|
+
bun run .github/scripts/build-stats.md.ts api >> $GITHUB_STEP_SUMMARY
|
|
38
|
+
|
|
39
|
+
- name: Check app build size
|
|
40
|
+
run: |
|
|
41
|
+
echo "## App" >> $GITHUB_STEP_SUMMARY
|
|
42
|
+
bun run .github/scripts/build-stats.md.ts app >> $GITHUB_STEP_SUMMARY
|
package/template/.gitignore
CHANGED
package/template/.npmrc
CHANGED
|
@@ -0,0 +1,330 @@
|
|
|
1
|
+
# Project Template
|
|
2
|
+
|
|
3
|
+
A full-stack application template with a Vue.js frontend, Bun-based API backend, PostgreSQL database, and Docker Compose setup for local development.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
This template provides a modern full-stack application structure with:
|
|
8
|
+
|
|
9
|
+
- **Frontend (app)**: Vue 3 application with Vite, UnoCSS, TypeScript, and TanStack Query
|
|
10
|
+
- **Backend (api)**: Bun-based API server with oRPC, Better Auth, and Drizzle ORM
|
|
11
|
+
- **Database**: PostgreSQL with Drizzle migrations
|
|
12
|
+
- **Infrastructure**: Docker Compose with Traefik reverse proxy, PostgreSQL, and Metabase
|
|
13
|
+
|
|
14
|
+
## Prerequisites
|
|
15
|
+
|
|
16
|
+
- [Bun](https://bun.sh/) (v1.3 or later)
|
|
17
|
+
- [Docker](https://docs.docker.com/get-docker/) and [Docker Compose](https://docs.docker.com/compose/install/)
|
|
18
|
+
- [Node.js LTS](https://nodejs.org/en/download/) (for compatibility)
|
|
19
|
+
- [mkcert](https://github.com/FiloSottile/mkcert) (for local TLS certificates)
|
|
20
|
+
|
|
21
|
+
## Project Structure
|
|
22
|
+
|
|
23
|
+
```
|
|
24
|
+
project/
|
|
25
|
+
├── api/ # Backend API server
|
|
26
|
+
│ ├── src/
|
|
27
|
+
│ │ ├── auth/ # Authentication setup (Better Auth)
|
|
28
|
+
│ │ ├── database/ # Database schema and migrations (Drizzle)
|
|
29
|
+
│ │ ├── orpc/ # Router definitions (oRPC)
|
|
30
|
+
│ │ ├── env.ts # Environment variable loading and validation (Valibot)
|
|
31
|
+
│ │ └── main.ts # API entry point
|
|
32
|
+
│ └── package.json
|
|
33
|
+
├── app/ # Frontend Vue application
|
|
34
|
+
│ ├── src/
|
|
35
|
+
│ │ ├── components/ # Vue components
|
|
36
|
+
│ │ ├── composables/ # Vue composables (auth, etc.)
|
|
37
|
+
│ │ ├── lib/ # Library utilities (oRPC client)
|
|
38
|
+
│ │ └── main.ts # App entry point
|
|
39
|
+
│ └── package.json
|
|
40
|
+
├── compose.yaml # Docker Compose configuration
|
|
41
|
+
└── package.json # Root workspace configuration
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Getting Started
|
|
45
|
+
|
|
46
|
+
### 1. Install Dependencies
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
bun install
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### 2. Set Up Environment Variables
|
|
53
|
+
|
|
54
|
+
> **Note**: If `.env.development` (API) or `.env` (App) files already exist in the template, you may skip this step. Otherwise, create them as described below.
|
|
55
|
+
|
|
56
|
+
#### API Environment Variables
|
|
57
|
+
|
|
58
|
+
Create a `.env.development` file in the `api/` directory with the following variables:
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
# api/.env.development
|
|
62
|
+
AUTH_SECRET=your-secret-key-here
|
|
63
|
+
DATABASE_URL=postgresql://user:password@postgres:5432/app
|
|
64
|
+
ALLOWED_ORIGINS=https://app.dev.localhost
|
|
65
|
+
LOG_LEVEL=info
|
|
66
|
+
HOST=0.0.0.0
|
|
67
|
+
PORT=4000
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
**Required variables:**
|
|
71
|
+
|
|
72
|
+
- `AUTH_SECRET` - Secret key for authentication encryption
|
|
73
|
+
- `DATABASE_URL` - PostgreSQL connection string
|
|
74
|
+
|
|
75
|
+
**Optional variables:**
|
|
76
|
+
|
|
77
|
+
- `ALLOWED_ORIGINS` - Comma-separated list of allowed CORS origins (default: empty)
|
|
78
|
+
- `LOG_LEVEL` - Logging level: `fatal`, `error`, `warn`, `info`, `debug`, `trace`, or `silent` (default: `info`)
|
|
79
|
+
- `HOST` - Server host (default: `0.0.0.0`)
|
|
80
|
+
- `PORT` - Server port (default: `4000`)
|
|
81
|
+
|
|
82
|
+
#### App Environment Variables
|
|
83
|
+
|
|
84
|
+
Create a `.env` file in the `app/` directory with the following variables:
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
# app/.env
|
|
88
|
+
VITE_API_URL=https://api.dev.localhost
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
**Required variables:**
|
|
92
|
+
|
|
93
|
+
- `VITE_API_URL` - API base URL for the frontend
|
|
94
|
+
|
|
95
|
+
### 3. Set Up Local TLS Certificates
|
|
96
|
+
|
|
97
|
+
To access the HTTPS URLs (`https://*.dev.localhost`), you need to set up trusted local TLS certificates using [mkcert](https://github.com/FiloSottile/mkcert).
|
|
98
|
+
|
|
99
|
+
Check their [installation guide](https://github.com/FiloSottile/mkcert#installation) for detailed instructions on installing mkcert.
|
|
100
|
+
|
|
101
|
+
Then, run the following command to generate the certificates:
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
.docker/traefik/bin/install_cert
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
This will generate the certificates in `.docker/traefik/certs/` and install the mkcert root CA into your system trust store.
|
|
108
|
+
|
|
109
|
+
> [!IMPORTANT]
|
|
110
|
+
> If your system is running on WSL and you are using Firefox or Zen Browser, **you must import the mkcert root CA into your browser trust store.**
|
|
111
|
+
>
|
|
112
|
+
> 1. Find the root CA file path:
|
|
113
|
+
> ```bash
|
|
114
|
+
> echo "wslpath -w $(mkcert -CAROOT)/rootCA.pem"
|
|
115
|
+
> # \\wsl.localhost\Ubuntu\home\user\.local\share\mkcert\rootCA.pem
|
|
116
|
+
> ```
|
|
117
|
+
> 2. Import the root CA file into your browser trust store:
|
|
118
|
+
> - **Settings** -> **Privacy & Security**.
|
|
119
|
+
> - **Certificates** -> **View Certificates...**
|
|
120
|
+
> - **Authorities** tab -> **Import...**
|
|
121
|
+
> - Select the rootCA.pem file (using the path found above)
|
|
122
|
+
> - Check **"Trust this CA to identify websites"**
|
|
123
|
+
> - Click **OK**
|
|
124
|
+
|
|
125
|
+
### 4. Start Docker Services and Access the Application
|
|
126
|
+
|
|
127
|
+
Start all services (Traefik, PostgreSQL, Metabase, API, and App):
|
|
128
|
+
|
|
129
|
+
```bash
|
|
130
|
+
docker compose up -d
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
Once the services are running, you can access:
|
|
134
|
+
|
|
135
|
+
- Frontend: https://app.dev.localhost
|
|
136
|
+
- API: https://api.dev.localhost
|
|
137
|
+
- Traefik Dashboard: https://traefik.dev.localhost
|
|
138
|
+
- Metabase: https://metabase.dev.localhost
|
|
139
|
+
|
|
140
|
+
### 5. Stopping Services
|
|
141
|
+
|
|
142
|
+
To stop all Docker services:
|
|
143
|
+
|
|
144
|
+
```bash
|
|
145
|
+
docker compose down
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
To stop and remove volumes (⚠️ this will delete database data):
|
|
149
|
+
|
|
150
|
+
```bash
|
|
151
|
+
docker compose down -v
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
## Development
|
|
155
|
+
|
|
156
|
+
### Running Services Locally (without Docker)
|
|
157
|
+
|
|
158
|
+
You can also run the services locally without Docker. Note that you'll still need PostgreSQL running (either locally or via Docker).
|
|
159
|
+
|
|
160
|
+
#### API Server
|
|
161
|
+
|
|
162
|
+
```bash
|
|
163
|
+
cd api
|
|
164
|
+
bun run dev
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
The API will run on `http://localhost:4000` (or the port specified in `PORT`).
|
|
168
|
+
|
|
169
|
+
#### Frontend App
|
|
170
|
+
|
|
171
|
+
```bash
|
|
172
|
+
cd app
|
|
173
|
+
bun run dev
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
The app will run on `http://localhost:5173` (Vite default port).
|
|
177
|
+
|
|
178
|
+
### Database Management
|
|
179
|
+
|
|
180
|
+
#### Generate Migrations
|
|
181
|
+
|
|
182
|
+
After modifying the database schema in `api/src/database/schema/`, generate migrations:
|
|
183
|
+
|
|
184
|
+
```bash
|
|
185
|
+
cd api
|
|
186
|
+
bun run db:generate
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
#### Run Migrations
|
|
190
|
+
|
|
191
|
+
Migrations run automatically when starting the API in dev mode. To run manually:
|
|
192
|
+
|
|
193
|
+
```bash
|
|
194
|
+
cd api
|
|
195
|
+
bun run db:migrate
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
## Available Scripts
|
|
199
|
+
|
|
200
|
+
### Root Level Scripts
|
|
201
|
+
|
|
202
|
+
- `bun run check` - Run all checks (ESLint, Stylelint, unused dependencies, TypeScript)
|
|
203
|
+
- `bun run lint` - Run linting (ESLint and Stylelint)
|
|
204
|
+
- `bun run lint:inspect` - Open ESLint config inspector
|
|
205
|
+
- `bun run update` - Update dependencies
|
|
206
|
+
|
|
207
|
+
### API Scripts (`cd api`)
|
|
208
|
+
|
|
209
|
+
- `bun run dev` - Start development server with hot reload
|
|
210
|
+
- `bun run build` - Build production binary
|
|
211
|
+
- `bun run db:generate` - Generate database migrations
|
|
212
|
+
- `bun run db:migrate` - Run database migrations
|
|
213
|
+
|
|
214
|
+
### App Scripts (`cd app`)
|
|
215
|
+
|
|
216
|
+
- `bun run dev` - Start development server with HMR (Hot Module Replacement)
|
|
217
|
+
- `bun run build` - Build for production (static site)
|
|
218
|
+
- `bun run build:analyze` - Build with bundle analyzer
|
|
219
|
+
- `bun run preview` - Preview production build
|
|
220
|
+
|
|
221
|
+
## Docker Compose Services
|
|
222
|
+
|
|
223
|
+
### Traefik
|
|
224
|
+
|
|
225
|
+
Reverse proxy and load balancer that handles:
|
|
226
|
+
|
|
227
|
+
- HTTPS termination
|
|
228
|
+
- SSL certificate management (requires certificates in `.docker/traefik/certs/`)
|
|
229
|
+
- Routing to services based on hostnames
|
|
230
|
+
- Dashboard accessible at https://traefik.dev.localhost
|
|
231
|
+
|
|
232
|
+
### PostgreSQL
|
|
233
|
+
|
|
234
|
+
Database service with:
|
|
235
|
+
|
|
236
|
+
- Default database: `app`
|
|
237
|
+
- Default user: `user`
|
|
238
|
+
- Default password: `password`
|
|
239
|
+
- Port: `5432`
|
|
240
|
+
- Persistent volume: `postgres_data`
|
|
241
|
+
|
|
242
|
+
### Metabase
|
|
243
|
+
|
|
244
|
+
Business intelligence tool for data visualization and analytics with:
|
|
245
|
+
|
|
246
|
+
- Persistent volume: `metabase_data`
|
|
247
|
+
- Accessible via Traefik at https://metabase.dev.localhost (runs on port `3000` internally)
|
|
248
|
+
|
|
249
|
+
### API
|
|
250
|
+
|
|
251
|
+
Backend API service running Bun with:
|
|
252
|
+
|
|
253
|
+
- Hot reload enabled
|
|
254
|
+
- Automatic database migrations on startup
|
|
255
|
+
- Health check endpoint: `/health`
|
|
256
|
+
- Auth endpoints: `/auth/*`
|
|
257
|
+
- RPC endpoints: `/rpc/*`
|
|
258
|
+
- Accessible via Traefik at https://api.dev.localhost (runs on port `4000` internally)
|
|
259
|
+
|
|
260
|
+
### App
|
|
261
|
+
|
|
262
|
+
Frontend Vue application with:
|
|
263
|
+
|
|
264
|
+
- Vite dev server
|
|
265
|
+
- Hot module replacement
|
|
266
|
+
- Accessible via Traefik at https://app.dev.localhost (runs on port `5173` internally)
|
|
267
|
+
|
|
268
|
+
## Environment Variables
|
|
269
|
+
|
|
270
|
+
For detailed environment variable setup, see [Set Up Environment Variables](#2-set-up-environment-variables) in the Getting Started section.
|
|
271
|
+
|
|
272
|
+
**Quick reference:**
|
|
273
|
+
|
|
274
|
+
- **API** (`.env.development`): `AUTH_SECRET` (required), `DATABASE_URL` (required), `ALLOWED_ORIGINS`, `LOG_LEVEL`, `HOST`, `PORT`
|
|
275
|
+
- **App** (`.env`): `VITE_API_URL` (required)
|
|
276
|
+
|
|
277
|
+
## Building for Production
|
|
278
|
+
|
|
279
|
+
### Build API
|
|
280
|
+
|
|
281
|
+
```bash
|
|
282
|
+
cd api
|
|
283
|
+
bun run build
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
This creates a compiled binary at `api/dist/api`.
|
|
287
|
+
|
|
288
|
+
### Build App
|
|
289
|
+
|
|
290
|
+
```bash
|
|
291
|
+
cd app
|
|
292
|
+
bun run build
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
This creates a static site in `app/dist/`.
|
|
296
|
+
|
|
297
|
+
## Troubleshooting
|
|
298
|
+
|
|
299
|
+
### Port Already in Use
|
|
300
|
+
|
|
301
|
+
If ports 80, 443, or 5432 are already in use, modify the port mappings in `compose.yaml`.
|
|
302
|
+
|
|
303
|
+
### SSL Certificate Warnings
|
|
304
|
+
|
|
305
|
+
If you see SSL certificate warnings when accessing `https://*.dev.localhost` URLs, ensure you have completed the [Local TLS Setup](#3-set-up-local-tls-certificates) to generate trusted certificates using mkcert.
|
|
306
|
+
|
|
307
|
+
**Note**: Without proper certificates, Traefik may fail to start or services may not be accessible via HTTPS.
|
|
308
|
+
|
|
309
|
+
### Service Logs
|
|
310
|
+
|
|
311
|
+
To view logs for a specific service:
|
|
312
|
+
|
|
313
|
+
```bash
|
|
314
|
+
docker compose logs -f <service-name>
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
For example:
|
|
318
|
+
|
|
319
|
+
- `docker compose logs -f api` - View API logs
|
|
320
|
+
- `docker compose logs -f app` - View app logs
|
|
321
|
+
- `docker compose logs -f traefik` - View Traefik logs
|
|
322
|
+
|
|
323
|
+
## Tech Stack
|
|
324
|
+
|
|
325
|
+
- **Runtime**: Bun
|
|
326
|
+
- **Language**: TypeScript
|
|
327
|
+
- **Frontend**: Vue 3, Vite, UnoCSS, TanStack Query
|
|
328
|
+
- **Backend**: Bun, oRPC, Better Auth, Drizzle ORM
|
|
329
|
+
- **Database**: PostgreSQL
|
|
330
|
+
- **Infrastructure**: Docker Compose, Traefik
|
|
@@ -1,24 +1,25 @@
|
|
|
1
1
|
{
|
|
2
|
-
"name": "
|
|
2
|
+
"name": "api",
|
|
3
3
|
"type": "module",
|
|
4
4
|
"private": true,
|
|
5
5
|
"scripts": {
|
|
6
|
-
"dev": "bun --watch --no-clear-screen src/main.ts",
|
|
7
|
-
"build": "bun build src/main.ts --compile --minify --sourcemap --outfile dist/
|
|
6
|
+
"dev": "bun run db:migrate 1> /dev/null && bun --watch --no-clear-screen src/main.ts | pino-pretty",
|
|
7
|
+
"build": "bun build src/main.ts --compile --minify --sourcemap --outfile dist/api",
|
|
8
8
|
"db:generate": "bun --bun run drizzle-kit generate --config src/database/drizzle/config.ts",
|
|
9
9
|
"db:migrate": "bun --bun run drizzle-kit migrate --config src/database/drizzle/config.ts"
|
|
10
10
|
},
|
|
11
11
|
"dependencies": {
|
|
12
|
-
"@
|
|
12
|
+
"@libsql/client": "^0.15.15",
|
|
13
|
+
"@orpc/server": "^1.11.2",
|
|
13
14
|
"better-auth": "^1.3.34",
|
|
14
15
|
"drizzle-orm": "^0.44.7",
|
|
15
16
|
"pino": "^10.1.0",
|
|
16
17
|
"valibot": "^1.1.0"
|
|
17
18
|
},
|
|
18
19
|
"devDependencies": {
|
|
19
|
-
"@
|
|
20
|
-
"
|
|
21
|
-
"
|
|
20
|
+
"@types/bun": "^1.3.2",
|
|
21
|
+
"drizzle-kit": "^0.31.7",
|
|
22
|
+
"pg": "^8.16.3",
|
|
22
23
|
"pino-pretty": "^13.1.2"
|
|
23
24
|
}
|
|
24
25
|
}
|
|
@@ -2,10 +2,13 @@ import { betterAuth } from 'better-auth'
|
|
|
2
2
|
import { type DB, drizzleAdapter } from 'better-auth/adapters/drizzle'
|
|
3
3
|
import type { BaseLogger } from 'pino'
|
|
4
4
|
|
|
5
|
+
import { env } from '../env'
|
|
6
|
+
|
|
5
7
|
export function createBetterAuth({ db, logger }: { db: DB, logger: BaseLogger }) {
|
|
6
8
|
return betterAuth({
|
|
7
9
|
basePath: '/auth',
|
|
8
|
-
|
|
10
|
+
secret: env.auth.secret,
|
|
11
|
+
trustedOrigins: env.cors.allowedOrigins,
|
|
9
12
|
database: drizzleAdapter(db, {
|
|
10
13
|
provider: 'pg',
|
|
11
14
|
usePlural: true,
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { defineConfig } from 'drizzle-kit'
|
|
2
2
|
|
|
3
|
+
import { env } from '../../env'
|
|
4
|
+
|
|
3
5
|
export default defineConfig({
|
|
4
6
|
casing: 'snake_case',
|
|
5
7
|
dialect: 'postgresql',
|
|
6
|
-
|
|
7
|
-
dbCredentials: { url: import.meta.env.DATABASE_URL },
|
|
8
|
+
dbCredentials: { url: env.database.url },
|
|
8
9
|
schema: 'src/database/schema',
|
|
9
10
|
out: 'src/database/migrations',
|
|
10
11
|
})
|
|
@@ -1,11 +1,13 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { logger } from '@server/utils/logger'
|
|
3
|
-
import { drizzle } from 'drizzle-orm/pglite'
|
|
1
|
+
import { drizzle } from 'drizzle-orm/bun-sql'
|
|
4
2
|
|
|
3
|
+
import { env } from '../env'
|
|
4
|
+
import { logger } from '../utils/logger'
|
|
5
5
|
import * as schema from './schema'
|
|
6
6
|
|
|
7
7
|
export const db = drizzle({
|
|
8
|
-
|
|
8
|
+
connection: {
|
|
9
|
+
url: env.database.url,
|
|
10
|
+
},
|
|
9
11
|
casing: 'snake_case',
|
|
10
12
|
schema,
|
|
11
13
|
logger: {
|