WIZλ Python Flask κΈ°λ°μ νμ€ν μΉ κ°λ° νλ μμν¬λ‘, Angularλ₯Ό μ½κ² μ¬μ©ν μ μλλ‘ μ€κ³λμμ΅λλ€. λ°±μλμ νλ‘ νΈμλλ₯Ό ν΅ν©νμ¬ κ΄λ¦¬νλ©°, νλ¬κ·ΈμΈ κΈ°λ° μν€ν μ²λ₯Ό ν΅ν΄ νμ₯ κ°λ₯ν IDE νκ²½μ μ 곡ν©λλ€.
season/
βββ __init__.py # ν¨ν€μ§ μ΄κΈ°ν λ° μ£Όμ API λ
ΈμΆ
βββ cmd.py # CLI λͺ
λ Ήμ΄ μνΈλ¦¬ν¬μΈνΈ
βββ version.py # λ²μ μ 보
βββ command/ # CLI λͺ
λ Ήμ΄ κ΅¬ν
β βββ bundle.py # λ²λ€λ§ κ΄λ ¨ λͺ
λ Ήμ΄
β βββ create.py # νλ‘μ νΈ μμ±
β βββ daemon.py # μλ² μ€ν λ° λ°λͺ¬ κ΄λ¦¬
β βββ ide.py # IDE κ΄λ ¨ λͺ
λ Ήμ΄
β βββ service.py # μμ€ν
μλΉμ€ κ΄λ¦¬
βββ lib/ # ν΅μ¬ λΌμ΄λΈλ¬λ¦¬
β βββ server.py # μλ² ν΄λμ€ (Flask + SocketIO)
β βββ core.py # Wiz ν΅μ¬ κΈ°λ₯
β βββ binding/ # HTTP λ° μμΌ λ°μΈλ©
β βββ static/ # μ μ 리μμ€ κ΄λ¦¬
β βββ ...
βββ util/ # μ νΈλ¦¬ν° ν¨μ
β βββ cache.py
β βββ compiler.py
β βββ filesystem.py
β βββ logger.py
β βββ string.py
βββ data/ # ν
νλ¦Ώ λ°μ΄ν°
βββ ide/ # IDE μμ€μ½λ
βββ plugin/ # νλ¬κ·ΈμΈ ν
νλ¦Ώ
βββ sample/ # μν νλ‘μ νΈ
βββ websrc/ # μΉ μμ€ ν
νλ¦Ώ
WIZ νλ μμν¬μ ν΅μ¬ μλ² ν΄λμ€λ‘, λ€μκ³Ό κ°μ κΈ°λ₯μ μ 곡ν©λλ€:
class Server:
def __init__(self, path=None):
self.boottime = time.time()
self.package = season.lib.static.Package()
self.path = season.lib.static.Path(path)
self.config = season.lib.static.Config(server=self)
self.cache = season.util.Cache()
# Flask λ° SocketIO μ ν리μΌμ΄μ
μ΄κΈ°ν
self.app.flask = Flask(...)
self.app.socketio = SocketIO(...)
# HTTP λ° μμΌ λ°μΈλ©
season.lib.binding.http(self)
season.lib.binding.socket(self)μ£Όμ κΈ°λ₯:
- Flask ν΅ν©: μΉ μλ² κΈ°λ³Έ κΈ°λ₯
- SocketIO ν΅ν©: μ€μκ° μλ°©ν₯ ν΅μ
- μ€μ κ΄λ¦¬:
config.bootκΈ°λ° κ΅¬μ± - μΊμ± μμ€ν : μ±λ₯ μ΅μ ν
- Wiz API:
wiz()λ©μλλ₯Ό ν΅ν νμ₯ API μ 곡
μμ±λ WIZ νλ‘μ νΈλ λ€μκ³Ό κ°μ ꡬ쑰λ₯Ό κ°μ§λλ€:
myapp/
βββ config/ # μ€μ νμΌ
β βββ boot.py # μλ² λΆν
μ€μ
β βββ ide.py # IDE μ€μ
β βββ service.py # μλΉμ€ μ€μ
β βββ plugin.json # νλ¬κ·ΈμΈ μ€μ
βββ public/ # κ³΅κ° λλ ν 리
β βββ app.py # μ ν리μΌμ΄μ
μνΈλ¦¬ν¬μΈνΈ
β βββ app.wsgi # WSGI μ€μ
βββ project/ # νλ‘μ νΈ λλ ν 리
β βββ main/ # λ©μΈ νλ‘μ νΈ
β βββ config/ # νλ‘μ νΈ μ€μ
β βββ src/ # μμ€ μ½λ
β β βββ app/ # Angular μ± μ»΄ν¬λνΈ
β β βββ controller/ # λ°±μλ 컨νΈλ‘€λ¬
β β βββ model/ # λ°μ΄ν° λͺ¨λΈ
β β βββ route/ # API λΌμ°νΈ
β β βββ portal/ # ν¬νΈ (μ¬μ¬μ© κ°λ₯ν λͺ¨λ)
β β βββ angular/ # Angular μ€μ
β β βββ assets/ # μ μ μμ°
β βββ build/ # λΉλ κ²°κ³Όλ¬Ό
β βββ bundle/ # λ²λ€ νμΌ
βββ ide/ # WIZ IDE μμ€
βββ plugin/ # νλ¬κ·ΈμΈ
β βββ core/
β βββ workspace/
β βββ git/
β βββ utility/
βββ wiz.pid # λ°λͺ¬ νλ‘μΈμ€ ID
src/app/ λλ ν 리λ Angular κΈ°λ°μ νλ‘ νΈμλ μ»΄ν¬λνΈλ₯Ό ν¬ν¨ν©λλ€.
ꡬ쑰 μμ:
src/app/
βββ layout.empty/ # λ μ΄μμ μ»΄ν¬λνΈ
β βββ view.pug
β βββ view.ts
β βββ view.scss
β βββ app.json
βββ page.main/ # νμ΄μ§ μ»΄ν¬λνΈ
βββ view.pug # Pug ν
νλ¦Ώ
βββ view.ts # TypeScript λ‘μ§
βββ view.scss # μ€νμΌμνΈ
βββ app.json # μ± λ©νλ°μ΄ν°
βββ api.py # λ°±μλ API
βββ socket.py # μμΌ νΈλ€λ¬
app.json μμ:
{
"title": "/workflow",
"mode": "page",
"namespace": "main",
"category": "general",
"id": "page.main",
"viewuri": "/workflow/**",
"layout": "layout.empty",
"ng": {
"selector": "wiz-page-main",
"inputs": [],
"outputs": []
}
}μ»΄ν¬λνΈ μ ν:
- Page: λΌμ°ν κ°λ₯ν νμ΄μ§ μ»΄ν¬λνΈ
- Layout: νμ΄μ§λ₯Ό κ°μΈλ λ μ΄μμ
- Widget: μ¬μ¬μ© κ°λ₯ν UI μ»΄ν¬λνΈ
src/controller/ λλ ν 리λ λ°±μλ λ‘μ§μ κΈ°λ³Έ 컨νΈλ‘€λ¬λ₯Ό μ μν©λλ€.
base.py μμ:
class Controller:
def __init__(self):
# μΈμ
μ΄κΈ°ν
wiz.session = wiz.model("portal/season/session").use()
sessiondata = wiz.session.get()
wiz.response.data.set(session=sessiondata)
# λ€κ΅μ΄ μ²λ¦¬
lang = wiz.request.query("lang", None)
if lang is not None:
wiz.response.lang(lang)
wiz.response.redirect(wiz.request.uri())μν :
- μΈμ κ΄λ¦¬
- μμ²/μλ΅ μ²λ¦¬
- κ³΅ν΅ λ‘μ§ κ΅¬ν
- μΈμ¦/μΈκ°
src/model/ λλ ν 리λ λ°μ΄ν° λͺ¨λΈκ³Ό λΉμ¦λμ€ λ‘μ§μ ν¬ν¨ν©λλ€.
νΉμ§:
- λ°μ΄ν°λ² μ΄μ€ μΆμν
- λΉμ¦λμ€ λ‘μ§ μΊ‘μν
- μ¬μ¬μ© κ°λ₯ν μ½λ ꡬ쑰
src/route/ λλ ν 리λ API μλν¬μΈνΈλ₯Ό μ μν©λλ€.
ꡬ쑰:
src/route/
βββ brand/
β βββ app.json
β βββ controller.py
βββ setting/
βββ app.json
βββ controller.py
controller.py μμ:
segment = wiz.request.match("/brand/<action>/<path:path>")
action = segment.action
if action == "logo":
# λ‘κ³ μ²λ¦¬ λ‘μ§
fs = wiz.project.fs("bundle", "src", "assets", "brand")
wiz.response.download(fs.abspath("logo.png"), as_attachment=False)
if action == "icon":
# μμ΄μ½ μ²λ¦¬ λ‘μ§
wiz.response.download(fs.abspath("icon.ico"), as_attachment=False)
wiz.response.abort(404)νΉμ§:
- RESTful API μ€κ³
- URL ν¨ν΄ λ§€μΉ
- νμΌ λ€μ΄λ‘λ λ° μ λ‘λ
- JSON μλ΅ μ²λ¦¬
src/portal/ λλ ν 리λ μ¬μ¬μ© κ°λ₯ν λͺ¨λ ν¨ν€μ§μ
λλ€.
ꡬ쑰:
src/portal/
βββ season/ # ν¬νΈ ν¨ν€μ§
β βββ portal.json # λ©νλ°μ΄ν°
β βββ app/ # Angular μ»΄ν¬λνΈ
β βββ controller/ # 컨νΈλ‘€λ¬
β βββ model/ # λͺ¨λΈ
β βββ route/ # λΌμ°νΈ
β βββ libs/ # λΌμ΄λΈλ¬λ¦¬
βββ dizest/
βββ ...
portal.json μμ:
{
"package": "season",
"title": "",
"version": "2.0.0",
"use_app": true,
"use_widget": false,
"use_route": true,
"use_libs": true,
"use_controller": true,
"use_model": true
}νΉμ§:
- λͺ¨λνλ κΈ°λ₯
- νλ‘μ νΈ κ° μ¬μ¬μ©
- λ 립μ μΈ λ€μμ€νμ΄μ€
- μ νμ κΈ°λ₯ νμ±ν
# λΆνΈμ€νΈλ© ν¨μ
def bootstrap(app, config):
pass
# μν¬λ¦Ώ ν€
secret_key = "season-wiz-secret"
# SocketIO μ€μ
socketio = dict()
socketio['async_mode'] = 'threading'
socketio['cors_allowed_origins'] = '*'
socketio['async_handlers'] = True
# μλ² μ€ν μ€μ
run = dict()
run['host'] = "0.0.0.0"
run['port'] = 3000
run['use_reloader'] = Falseμ€μ νλͺ©:
bootstrap: μλ² μμ μ μ€νλλ ν¨μsecret_key: Flask μΈμ μνΈν ν€socketio: SocketIO μλ² μ΅μ run: μλ² μ€ν μ΅μ (host, port λ±)
WIZλ κ°λ ₯ν νλ¬κ·ΈμΈ μν€ν μ²λ₯Ό μ 곡ν©λλ€.
νλ¬κ·ΈμΈ ꡬ쑰:
plugin/
βββ core/ # ν΅μ¬ νλ¬κ·ΈμΈ
βββ workspace/ # μν¬μ€νμ΄μ€ κ΄λ¦¬
β βββ app/
β βββ command.py # CLI λͺ
λ Ήμ΄
β βββ filter.py
β βββ model/
β βββ plugin.json
βββ git/ # Git ν΅ν©
βββ utility/ # μ νΈλ¦¬ν°
βββ xterm/ # ν°λ―Έλ
command.py μμ:
def build(*args):
if len(args) < 1:
print("wiz command workspace build [projectName]")
return
project = args[0]
wiz.project.checkout(project)
builder = wiz.ide.plugin.model("builder")
builder.build()νλ¬κ·ΈμΈ κΈ°λ₯:
- 컀μ€ν CLI λͺ λ Ήμ΄
- IDE νμ₯
- λ°±μλ API μΆκ°
- νλ‘ νΈμλ μμ ―
WIZλ μΉ κΈ°λ° IDEλ₯Ό λ΄μ₯νμ¬ νλ‘μ νΈλ₯Ό λΈλΌμ°μ μμ μ§μ κ°λ°ν μ μμ΅λλ€.
IDE ꡬ쑰:
ide/
βββ package.json
βββ angular/ # Angular μ€μ
β βββ angular.build.options.json
β βββ index.html
β βββ main.ts
β βββ wiz.ts
β βββ wizbuild.js
βββ app/ # IDE μ± μ»΄ν¬λνΈ
β βββ core.app.ide/
β βββ core.editor.monaco/
β βββ workspace.app.explore/
β βββ ...
βββ assets/
μ£Όμ κΈ°λ₯:
- νμΌ νμκΈ°
- μ½λ μλν° (Monaco Editor)
- ν°λ―Έλ
- Git ν΅ν©
- μ€μκ° λ―Έλ¦¬λ³΄κΈ°
WIZλ Angular νλ‘μ νΈλ₯Ό μλμΌλ‘ λΉλν©λλ€.
λΉλ νλ‘μΈμ€:
- TypeScript μ»΄νμΌ
- Pug ν νλ¦Ώ λ³ν
- SCSS μ»΄νμΌ
- Angular λ²λ€λ§
- μ΅μ ν λ° μμΆ
λΉλ λͺ λ Ήμ΄:
wiz command workspace build main- RESTful API
- JSON μμ²/μλ΅
- νμΌ μ λ‘λ/λ€μ΄λ‘λ
- μ€μκ° μλ°©ν₯ ν΅μ
- μ΄λ²€νΈ κΈ°λ° λ©μμ§
- λ€μμ€νμ΄μ€ μ§μ
μμΌ νΈλ€λ¬ μμ (socket.py):
def connect():
# ν΄λΌμ΄μΈνΈ μ°κ²° μ
pass
def disconnect():
# ν΄λΌμ΄μΈνΈ μ°κ²° ν΄μ μ
pass
def on_message(data):
# λ©μμ§ μμ μ
wiz.response.send({"result": "ok"})Browser β Flask Router β Controller β Model β Response
β
Route (API)
β
App (API Handler)
URL Request β Route Matching β Layout Load β Page Component Load
β
Angular Rendering
β
API Calls (api.py)
Client Event β SocketIO Namespace β socket.py Handler β Response
β
Business Logic
- λ©ν° νλ‘μΈμ€ μ§μ
- λ‘λ λ°Έλ°μ± κ°λ₯
- νλ¬κ·ΈμΈμ ν΅ν κΈ°λ₯ μΆκ°
- ν¬νΈ μμ€ν μ ν΅ν λͺ¨λ μ¬μ¬μ©
- 컀μ€ν μ»΄ν¬λνΈ κ°λ°
- WSGI νμ€ μ§μ
- λ€μν μΉ μλ²μ νΈν (Nginx, Apache λ±)
- 컨ν μ΄λν μ§μ (Docker)
- Flask μΈμ κΈ°λ°
- Secret Key μνΈν
- SocketIO CORS μ§μ
- λλ©μΈλ³ μ κ·Ό μ μ΄
- 컀μ€ν μΈμ¦ μμ€ν ꡬν κ°λ₯
- μΈμ κΈ°λ° κΆν κ΄λ¦¬
- μλ² λ 벨 μΊμ (
season.util.Cache) - μ μ νμΌ μΊμ±
- Angular AOT μ»΄νμΌ
- μ½λ μ€ν리ν
- μμΆ λ° μ΅μν
- SocketIO λΉλκΈ° νΈλ€λ¬
- λ©ν°μ€λ λ© μ§μ
WIZλ Flaskμ Angularμ ν΅ν©ν νμ€ν νλ μμν¬λ‘, λ€μκ³Ό κ°μ νΉμ§μ κ°μ§λλ€:
- ν΅ν© κ°λ° νκ²½: λ°±μλμ νλ‘ νΈμλλ₯Ό νλμ νλ‘μ νΈλ‘ κ΄λ¦¬
- νλ¬κ·ΈμΈ μν€ν μ²: νμ₯ κ°λ₯νκ³ λͺ¨λνλ ꡬ쑰
- μΉ κΈ°λ° IDE: λΈλΌμ°μ μμ μ§μ κ°λ° κ°λ₯
- μ€μκ° ν΅μ : SocketIOλ₯Ό ν΅ν μλ°©ν₯ ν΅μ
- κ°νΈν λ°°ν¬: CLIλ₯Ό ν΅ν νλ‘μ νΈ κ΄λ¦¬ λ° μλΉμ€ λ±λ‘
μ΄λ¬ν μν€ν μ²λ₯Ό ν΅ν΄ WIZλ λΉ λ₯΄κ³ ν¨μ¨μ μΈ μΉ μ ν리μΌμ΄μ κ°λ°μ μ§μν©λλ€.