언어는 하나.
바이너리도 하나.
웹의 모든 것.
SpaceFive는 순수 Five로 만든, 필요한 것이 다 들어 있는 웹 프레임워크입니다. HTTP와 WebSocket, PostgreSQL, bcrypt, AES, 다국어까지 런타임이 직접 처리합니다. Node도, FFI도, ORM 서버도 없습니다. 정적 바이너리 하나가 Postgres와 바로 통하고, 그 위에서 진짜 앱 세 개가 지금 이 순간 돌아가고 있습니다.
앱은 셋, 프레임워크는 하나,
디자인도 하나.
클릭하는 모든 것이 Five 핸들러의 응답입니다. 화면 일부만 바꾸는 하이퍼미디어 갱신, 서버에서 그린 폼, CSV 내보내기, 사진 업로드, 실시간 이벤트까지.
자산관리
갤러리·목록·상세 화면, 검색과 상태·분류 필터, 여러 통화의 금액, 클릭 한 번이면 끝나는 CSV 내보내기.
인사관리
직책, 부서, 급여, 사진이 있는 직원 명부. 자산관리와 똑같은 셸, 똑같은 칩, 똑같은 카드로 만들었습니다.
영업관리 ERP
거래처·품목·수주를 여신 관리, 재고, 출하, 청구, 수금, 채권 연령까지 한 흐름으로. 대시보드, 인쇄용 전표, 보고서 포함.
이 언어, 이미 알고 계십니다.
달라진 건 화면뿐입니다.
Clipper나 FoxPro, Harbour로 코드를 짜 보셨다면 SpaceFive 페이지는 수백 번 만들어 본 다이얼로그처럼 읽힙니다. 아래 예제는 전부 진짜입니다. 오른쪽 위젯은 왼쪽 코드가 지금 이 요청에서 직접 그린 결과입니다.
MENU hMenu MENUBAR MENUITEM "Assets" ACTION "/assets" MENUITEM "People" ACTION "/people" MENUITEM "+ New asset" ACTION "/assets/new" GOLD ENDMENU cHtml := MENU_HTML( hMenu )
hStat := DB_ONE( cAssetStats, {} ) DASHBOARD hDash STAT "Total assets" VALUE hStat[ "n" ] GOLD STAT "Total value" VALUE Money( hStat[ "total" ], "USD" ) GOLD STAT "Active" VALUE hStat[ "active" ] OK STAT "In maintenance" VALUE hStat[ "maint" ] WARN ENDDASHBOARD cHtml := DASH_HTML( hDash )
aRows := DB_QUERY( cFirstEmployees, {} ) TABLE hList OF aRows LINK "/people/:id" COLUMN "name" HEADER "Employee" THUMB "photo" SUB "emp_no" COLUMN "position" HEADER "Position" COLUMN "status" HEADER "Status" BADGE COLUMN "salary" HEADER "Salary" MONEY CURRENCY "currency" RIGHT ENDTABLE cHtml := TABLE_HTML( hList )
GALLERY hCards OF aRows LINK "/people/:id" CARD PHOTO "photo" INITIALS "name" CARD BADGE "status" CARD TAG "position" CARD TITLE "name" CARD META "department" CARD VALUE "salary" CURRENCY "currency" ENDGALLERY cHtml := GALLERY_HTML( hCards )
FORM hForm ACTION "/people" OF hReq GET "emp_no" LABEL "Employee no." VALUE "E-2001" GET "name" LABEL "Name" COMBO "status" LABEL "Status" VALUE "active" ITEMS aStatuses GET "salary" LABEL "Salary (annual)" VALUE 90000 BUTTON "Save" GOLD LINK "Cancel" ACTION "/" ENDFORM cHtml := FORM_HTML( hForm )
DOS 화면에서 브라우저로
| 예전에는 이렇게 | 지금은 이렇게 | 무엇을 하나 |
|---|---|---|
| @ 10, 5 SAY "Name" GET cName | GET "name" LABEL "Name" VALUE cName | 라벨이 붙은 입력 칸 하나. |
| MENU oMenu … MENUITEM … ENDMENU | MENU hMenu MENUBAR … MENUITEM … ENDMENU | 헤더 버튼도, 사이드바 칩도, 탭도 같은 문법으로. |
| TBrowse / dbEdit() | TABLE hList OF aRows … COLUMN … ENDTABLE | 썸네일, 배지, 금액 열이 있는 클릭형 목록. |
| USE customers INDEX ON name | aRows := DB_QUERY( cSql, { cName } ) | PostgreSQL에 파라미터를 바인딩해 바로 조회. ORM 서버는 없습니다. |
| SET COLOR TO W+/B | public/skins/<skin>/skin.css | 생김새는 스킨의 몫. 디자이너가 고칠 수 있는 CSS와 작은 HTML 템플릿입니다. |
| ACTIVATE WINDOW oWnd | FV_SERVE( nPort, "public", {| hReq | APP_DISPATCH( hReq ) } ) | 웹 서버 전체가 main.prg의 한 줄입니다. |
런타임이 직접, 중간 다리 없이.
모든 층이 Five 런타임 라이브러리 호출입니다. PostgreSQL 말고는 설치할 게 없습니다.
FV_SERVEHTTP, 처음부터 끝까지
헤더와 쿠키를 받고, 상태 코드와 set-cookie를 돌려줍니다. 요청마다 전용 VM 스레드에서 돕니다.
WsServe · WsSend실시간
의존성 없는 WebSocket 서버. 이 페이지 아래의 피드가 지금 그것을 듣고 있습니다.
PG_OPEN · PG_QUERYPostgreSQL 직결
pgx 위에서 파라미터를 바인딩한 쿼리. 마이그레이션은 부팅 때 자동으로, 몇 번을 돌려도 같은 결과입니다.
PWHASH · ENCRYPT · SECEQ기본 설정부터 안전하게
bcrypt 비밀번호, AES-256-GCM 세션, 상수 시간 비교, CSRF 이중 제출.
T()다국어 내장
카탈로그 기반 번역에 요청마다 로케일 결정. 지금 보시는 이 페이지도 locales/*.json에서 여섯 언어로 나갑니다.
hx.js하이퍼미디어 UI
54줄짜리 HTMX식 심 하나. 부분 교체와 CSRF 헤더만 있고, 빌드 단계도 프레임워크도 없습니다.
요청도 해시, 응답도 해시.
핸들러는 코드블록 하나.
지금 돌고 있는 앱의 실제 라우트 테이블과 실제 핸들러입니다.
// asset manager — gallery, list, detail, CRUD, export ROUTE( "GET", "/assets", {| hReq | ASSET_DASHBOARD( hReq ) } ) ROUTE( "GET", "/assets/cards", {| hReq | ASSET_CARDS( hReq ) } ) ROUTE( "POST", "/assets", {| hReq | ASSET_CREATE( hReq ) } ) ROUTE( "GET", "/assets/export.csv", {| hReq | ASSET_EXPORT( hReq ) } ) // main.prg — the whole server FV_SERVE( hCfg[ "port" ], "public", {| hReq | APP_DISPATCH( hReq ) } ) // a handler: query → hash → JSON. The result lives in a variable; RETURN returns it. FUNCTION ASSET_LIST( hReq ) LOCAL aRows := Rows( hReq, 1000, 0 ) LOCAL hRes := RES_JSON( { "ok" => .T., "assets" => aRows, "count" => Len( aRows ) } ) RETURN hRes






