Sonamu๋ create-sonamu ํจํค์ง๋ฅผ ํตํด ํ๋ก์ ํธ๋ฅผ ์์ฝ๊ฒ ์์ํ ์ ์์ต๋๋ค.
์์คํ
์๊ตฌ์ฌํญ
Sonamu๋ฅผ ์ฌ์ฉํ๊ธฐ ์ํด์๋ ๋ค์ ํ๊ฒฝ์ด ํ์ํฉ๋๋ค:
Node.js v22 ์ด์
pnpm v10.23 ์ด์
Docker (๋ฐ์ดํฐ๋ฒ ์ด์ค ์คํ์ฉ)
pnpm์ด ์ค์น๋์ง ์์๋ค๋ฉด corepack enable ๋ช
๋ น์ด๋ก ํ์ฑํํ ์ ์์ต๋๋ค.
ํ๋ก์ ํธ ์์ฑ
ํฐ๋ฏธ๋์์ ๋ค์ ๋ช
๋ น์ด๋ฅผ ์คํํ์ฌ ์ Sonamu ํ๋ก์ ํธ๋ฅผ ์์ฑํฉ๋๋ค:
์ธ๋ผ์ธ ์ต์
ํ๋ก์ ํธ๋ช
์ ์ธ์๋ก ์ ๋ฌํ๊ฑฐ๋, ์ต์
์ ํตํด ๋ํํ ํ๋กฌํํธ๋ฅผ ๊ฑด๋๋ธ ์ ์์ต๋๋ค:
# ํ๋ก์ ํธ๋ช
์ง์ ์ง์
pnpm create sonamu myapp
# ๋ชจ๋ ์ต์
์ ๊ธฐ๋ณธ๊ฐ์ผ๋ก ์ค์ (๋น๋ํํ)
pnpm create sonamu myapp --yes
# pnpm/docker ์ค์ ์ฌ๋ถ๋ฅผ ๋ช
์์ ์ผ๋ก ์ง์
pnpm create sonamu myapp --pnpm y --docker y
# pnpm๋ง ์๋ ์งํ (docker๋ ํ๋กฌํํธ๋ก ๋ฌผ์ด๋ด)
pnpm create sonamu myapp --pnpm y
# docker๋ง ์๋ ์งํ (pnpm์ ํ๋กฌํํธ๋ก ๋ฌผ์ด๋ด, DB ์ต์
์ ๊ธฐ๋ณธ๊ฐ)
pnpm create sonamu myapp --docker y
# ์์ ํ ๋น๋ํํ ๋ชจ๋ (๋ชจ๋ ์ต์
์ง์ )
pnpm create sonamu myapp \
--pnpm y \
--docker y \
--db-user=postgres \
--db-password=1234 \
--db-name=myapp \
--container-name=myapp-pg \
--docker-project=myapp-docker
# DB ์ต์
๋ง ์ง์ (pnpm/docker ์ค์ ์ ํ๋กฌํํธ๋ก ๋ฌผ์ด๋ด)
pnpm create sonamu myapp --db-name myapp --db-password secret123
์ต์
์ค๋ช
๊ธฐ๋ณธ๊ฐ --yes, -y๋ชจ๋ ์ต์
์ ๊ธฐ๋ณธ๊ฐ์ผ๋ก ์ค์ - --pnpmpnpm ์ค์น ์ฌ๋ถ (y/n) (ํ๋กฌํํธ๋ก ์ง๋ฌธ) --dockerDocker DB ์ค์ ์ฌ๋ถ (y/n) (ํ๋กฌํํธ๋ก ์ง๋ฌธ) --skip-pnpmpnpm ์ค์ ๊ฑด๋๋ฐ๊ธฐ (--pnpm n๊ณผ ๋์ผ) false --skip-dockerDocker DB ์ค์ ๊ฑด๋๋ฐ๊ธฐ (--docker n๊ณผ ๋์ผ) false --docker-project, --docker-pj-nameDocker Compose ํ๋ก์ ํธ๋ช
-docker --db-user๋ฐ์ดํฐ๋ฒ ์ด์ค ์ฌ์ฉ์๋ช
postgres --db-name๋ฐ์ดํฐ๋ฒ ์ด์ค ์ด๋ฆ --db-password๋ฐ์ดํฐ๋ฒ ์ด์ค ๋น๋ฐ๋ฒํธ 1234 --container-nameDocker ์ปจํ
์ด๋ ์ด๋ฆ -container
--pnpm y, --docker y์์ y๋ yes, true, 1๋ก๋ ์ง์ ํ ์ ์์ต๋๋ค. ๋ง์ฐฌ๊ฐ์ง๋ก n์ no, false, 0์ผ๋ก๋ ์ง์ ํ ์ ์์ต๋๋ค.
๋ํํ ํ๋กฌํํธ๊ฐ ๋ํ๋๋ฉด ํ๋ก์ ํธ ์ ๋ณด๋ฅผ ์
๋ ฅํฉ๋๋ค:
? Project name: myapp
? Would you like to set up pnpm ? Yes
? Would you like to set up a database using Docker ? Yes
? Enter the Docker project name: myapp-docker
? Enter the database user: postgres
? Enter the container name: myapp-container
? Enter the database name: myapp
? Enter the database password: ****
ํ๋ก์ ํธ๋ช
์
๋ ฅ
์์ฑํ ํ๋ก์ ํธ์ ์ด๋ฆ์ ์
๋ ฅํฉ๋๋ค. ์ด ์ด๋ฆ์ผ๋ก ๋๋ ํ ๋ฆฌ๊ฐ ์์ฑ๋ฉ๋๋ค. ํ๋ก์ ํธ๋ช
์๋ ๊ณต๋ฐฑ ๊ณผ **ํ์ดํ(-)**์ ์ฌ์ฉํ ์ ์์ต๋๋ค. ์ธ๋์ค์ฝ์ด(_)๋ฅผ ์ฌ์ฉํ์ธ์.
pnpm ์ค์
pnpm์ ์๋์ผ๋ก ์ค์ ํ ์ง ์ ํํฉ๋๋ค. ๊ถ์ฅ ์ต์
์
๋๋ค.
๋ฐ์ดํฐ๋ฒ ์ด์ค ์ค์
Docker๋ฅผ ์ฌ์ฉํ PostgreSQL ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ฅผ ์ค์ ํ ์ง ์ ํํฉ๋๋ค. Yes๋ฅผ ์ ํํ๋ฉด:
Docker Compose ํ๋ก์ ํธ๋ช
๋ฐ์ดํฐ๋ฒ ์ด์ค ์ฌ์ฉ์๋ช
์ปจํ
์ด๋ ์ด๋ฆ
๋ฐ์ดํฐ๋ฒ ์ด์ค ์ด๋ฆ
๋ฐ์ดํฐ๋ฒ ์ด์ค ๋น๋ฐ๋ฒํธ
๋ฅผ ์
๋ ฅ๋ฐ๊ณ , ์ด ์ ๋ณด๋ก packages/api/.env ํ์ผ์ด ์๋ ์์ฑ๋ฉ๋๋ค.
์์ฑ๋ ํ๋ก์ ํธ ๊ตฌ์กฐ
create-sonamu๋ ๋ค์๊ณผ ๊ฐ์ ๋ชจ๋
ธ๋ ํฌ ๊ตฌ์กฐ๋ฅผ ์์ฑํฉ๋๋ค:
api (๋ฐฑ์๋ API ์๋ฒ) web (ํ๋ก ํธ์๋ ์น ์ฑ) pnpm-workspace.yaml (์ํฌ์คํ์ด์ค ์ค์ )
์ฃผ์ ์ค์ ํ์ผ
pnpm ์ํฌ์คํ์ด์ค
๋ฃจํธ์ pnpm-workspace.yaml์์ ๋ชจ๋
ธ๋ ํฌ ํจํค์ง์ ๊ณตํต ์์กด์ฑ ๋ฒ์ ์ ๊ด๋ฆฌํฉ๋๋ค:
packages :
- packages/api
- packages/web
catalog :
"@tanstack/react-query" : ^5.90.12
"@tanstack/react-router" : 1.143.11
react : ^19.2.3
vite : 7.3.0
vitest : 4.0.16
# ... ๊ธฐํ ๊ณตํต ์์กด์ฑ
API ์๋ฒ ์ํธ๋ฆฌํฌ์ธํธ
์์ฑ๋ API ์๋ฒ์ ์ง์
์ ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค:
Sonamu ์ค์
sonamu.config.ts์์ ํ๋ก์ ํธ์ ์ฃผ์ ์ค์ ์ ๊ด๋ฆฌํฉ๋๋ค:
packages/api/src/sonamu.config.ts
import path from "node:path" ;
import { CachePresets , defineConfig } from "sonamu" ;
import { drivers as cacheDrivers , store } from "sonamu/cache" ;
import { drivers } from "sonamu/storage" ;
const host = "localhost" ;
const port = 1028 ;
export default defineConfig ({
projectName: process . env . PROJECT_NAME ?? "SonamuProject" ,
api: {
dir: "api" ,
timezone: "Asia/Seoul" ,
route: {
prefix: "/api" ,
},
} ,
i18n: {
defaultLocale: "ko" ,
supportedLocales: [ "ko" , "en" ],
} ,
sync: {
targets: [ "web" ],
} ,
database: {
database: "pg" ,
name: process . env . DATABASE_NAME ?? "database_name" ,
defaultOptions: {
connection: {
host: process . env . DB_HOST || "0.0.0.0" ,
port: Number ( process . env . DB_PORT ) || 5432 ,
user: process . env . DB_USER || "postgres" ,
password: process . env . DB_PASSWORD ,
},
},
} ,
server: {
listen: { port , host },
// ... ์๋ฒ, ์คํ ๋ฆฌ์ง, ์บ์ ์ค์
cache: {
default: "main" ,
stores: {
main: store (). useL1Layer ( cacheDrivers . memory ({ maxSize: "50mb" })),
},
ttl: "5m" ,
},
} ,
}) ;
Docker Compose ์ค์
PostgreSQL ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ Docker๋ก ๊ด๋ฆฌ๋ฉ๋๋ค:
packages/api/database/docker-compose.yml
version : "3.8"
name : ${CONTAINER_NAME}
services :
pg :
platform : linux/arm64
image : pgvector/pgvector:pg18
container_name : ${CONTAINER_NAME}
env_file :
- ../.env
volumes :
- ./fixtures/init.sh:/docker-entrypoint-initdb.d/init.sh
environment :
DATABASE_NAME : ${DATABASE_NAME}
POSTGRES_DB : template1
POSTGRES_USER : ${DB_USER}
POSTGRES_PASSWORD : ${DB_PASSWORD}
TZ : Asia/Seoul
ports :
- "${DB_PORT}:5432"
ํ๋ก ํธ์๋ ์ค์
Vite + React + TanStack Router + SSR ๊ธฐ๋ฐ ์ ํ๋ฆฌ์ผ์ด์
์ด ์์ฑ๋ฉ๋๋ค:
packages/web/vite.config.ts
import tailwindcss from "@tailwindcss/vite" ;
import { tanstackRouter } from "@tanstack/router-plugin/vite" ;
import react from "@vitejs/plugin-react-swc" ;
import dotenv from "dotenv" ;
import path from "path" ;
import Icons from "unplugin-icons/vite" ;
import { defineConfig } from "vite" ;
dotenv . config ({ path: ".sonamu.env" });
export default defineConfig (({ command , isSsrBuild }) => ({
plugins: [
react (),
Icons ({ compiler: "jsx" , jsx: "react" , autoInstall: true }),
tailwindcss (),
tanstackRouter (),
] ,
resolve: {
alias: {
"@" : path . resolve ( __dirname , "./src" ),
},
} ,
server: {
host: "0.0.0.0" ,
port: 3028 ,
proxy: {
"/api" : `http:// ${ process . env . API_HOST } : ${ process . env . API_PORT } ` ,
},
} ,
// SSR ์ค์ ํฌํจ
})) ;
ํฌํธ ๊ตฌ์ฑ
๊ธฐ๋ณธ ํฌํธ๋ ๋ค์๊ณผ ๊ฐ์ด ์ค์ ๋ฉ๋๋ค:
์๋น์ค ํฌํธ ์ค๋ช
API ์๋ฒ 1028 Fastify ๊ธฐ๋ฐ REST API Sonamu UI - http://localhost:1028/sonamu-ui Web ์ฑ 3028 Vite ๊ฐ๋ฐ ์๋ฒ (SSR ์ง์) PostgreSQL 5432 ๋ฐ์ดํฐ๋ฒ ์ด์ค
Sonamu UI : ๋ณ๋ ํฌํธ๊ฐ ์๋ API ์๋ฒ์ /sonamu-ui ๊ฒฝ๋ก๋ก ์ ๊ทผํฉ๋๋ค.
API ์๋ฒ ํฌํธ: packages/api/src/sonamu.config.ts์์ port ์์ ์์ (์ด ๊ฒฝ์ฐ packages/web/.sonamu.env์ API_PORT๋ ํจ๊ป ์์ ํ์)
Web ์ฑ ํฌํธ: packages/web/vite.config.ts์์ server.port ์์
๋ค์ ๋จ๊ณ
์ค์น๊ฐ ์๋ฃ๋์๋ค๋ฉด, ๋น ๋ฅธ ์์ ๊ฐ์ด๋๋ฅผ ํตํด ์ฒซ ๋ฒ์งธ ์ํฐํฐ๋ฅผ ์์ฑํ๊ณ API๋ฅผ ๋ง๋ค์ด๋ณด์ธ์.