Every application built on Gingee follows a simple and consistent structure. This guide breaks down that structure, explains the critical role of the box
folder, and provides a comprehensive reference for all the settings available in the app.json
and routes.json
configuration file.
Every first-level directory inside your server's web
root is considered a distinct App. For an application named my_app
, the structure looks like this:
web/
└── my_app/
├── box/
├── css/
├── images/
├── scripts/
└── index.html
my_app/
: The root folder for the application. The name of this folder becomes the app's unique ID and the first segment of its URL (e.g., http://localhost/my_app/...
).
css/
, images/
, scripts/
, etc.: These are public directories. Any file placed here can be accessed directly by its URL. Gingee's static file server will serve these assets. For example, a file at web/my_app/css/style.css
is available at /my_app/css/style.css
.
index.html
: If a user navigates to the app's root URL (/my_app
), this file will be served by default (if the app is not an SPA).
box
FolderThe box
folder is the private, secure core of your application. It contains all your backend logic, configuration, and private data.
Security: The box
folder is always protected. No file inside the box
can ever be accessed directly from a URL. A request to /my_app/box/app.json
, for example, will be blocked with a 403 Access Denied
error. This is a fundamental security guarantee of the Gingee platform.
Server Scripts: All your backend API endpoints are JavaScript files that live inside the box
. A request to /my_app/api/users
is mapped to the file at web/my_app/box/api/users.js
.
Configuration: All app-specific configuration, including the crucial app.json
file, resides in the box
.
Private Data: If your application uses a file-based database like SQLite, its database file should be stored in a subdirectory within the box
(e.g., box/data/app.db
) to ensure it is protected from direct web access.
app.json
File:The app.json
file, located at web/my_app/box/app.json
, is the central configuration file for your application. It tells the Gingee server how to handle the app, what resources it needs, and how it should behave.
Here is a comprehensive breakdown of all available properties.
{
"name": "My Awesome App",
"description": "This is a demonstration of all app.json settings.",
"version": "1.2.0",
"type": "MPA",
"mode": "production",
"spa": {
"enabled": false,
"dev_server_proxy": "http://localhost:5173",
"build_path": "./dist",
"fallback_path": "index.html"
},
"db": [],
"startup_scripts": [],
"default_include": [],
"env": {},
"jwt_secret": "a-very-strong-and-unique-secret-key",
"cache": {
"client": {
"enabled": true,
"no_cache_regex": ["/api/realtime"]
},
"server": {
"enabled": true,
"no_cache_regex": ["/api/dynamic-script.js"]
}
}
}
name
(string, required)description
(string, optional)version
(string, optional)type
(string, optional)
"MPA"
(Multi-Page Application): The default."SPA"
(Single Page Application - NOT IMPLEMENTED YET): Activates "SPA Fallback" for client-side routing.mode
(string, optional)
"production"
(Default): The standard mode for live servers. For SPAs, this serves the compiled static assets from the build_path
."development"
: Activates development-only features. For SPAs, this enables the seamless dev server proxy.spa
object)This object is only used when app is of "type": "SPA"
.
spa.enabled
(boolean, required): Must be true
to activate SPA features.spa.dev_server_proxy
(string, optional): (Development only) The full URL of your frontend's hot-reloading development server (e.g., Vite, Angular CLI). Gingee will proxy all non-API requests to this URL when the app's mode
is "development"
.spa.build_path
(string, required): (Production only) The path to the directory containing your compiled frontend assets, relative to the app's root folder (e.g., ./dist
).spa.fallback_path
(string, required): (Production only) The path to the SPA's entrypoint file (usually index.html
) within the build_path
. Gingee serves this file for any request that doesn't match an API route or a static asset, enabling client-side routing.db
(array, optional)
type
, name
, host
, user
, password
, database
, etc.startup_scripts
(array, optional)
box
folder."startup_scripts": ["setup/01_schema.js", "setup/02_seed_data.js"]
default_include
(array, optional)
"lib/auth.js"
), it is resolved as a path relative to the app's box
folder."auth"
), it is resolved from the global modules
folder."default_include": ["auth_middleware.js", "lib/request_logger.js"]
env
(object, optional)
$g.app.env
.jwt_secret
(string, optional)
auth
module for creating and verifying JSON Web Tokens (JWTs).cache
(object, optional)
cache.client
: Controls browser caching (Cache-Control
header).cache.server
: Controls server-side caching of static files and transpiled scripts in Memory or Redis.pmft.json
File (Permissions Manifest)If you plan to distribute your application as a .gin
package, you must declare the permissions it requires in a pmft.json
file. This manifest is read by the gingee-cli
during the installation process to request consent from the server administrator.
web/<your-app-name>/box/pmft.json
mandatory
) and optional (optional
) permissions.For a complete guide on the permissions system and the structure of this file, please see the Gingee Permissions Guide MD HTML.
routes.json
File (Manifest-Based Routing)For applications that require more powerful and flexible routing, such as RESTful APIs with dynamic path parameters, you can create a routes.json
file. When this file is present in an app's box
folder, it activates manifest-based routing, which takes precedence over the default file-based routing.
web/my-app/box/routes.json
routes.json
The file must contain a single root object with a routes
key, which holds an array of route definition objects.
{
"routes": [
{
"path": "/users",
"method": "GET",
"script": "users/list.js"
},
{
"path": "/users/:userId",
"method": "GET",
"script": "users/get.js"
},
{
"path": "/users/:userId",
"method": "PUT",
"script": "users/update.js"
},
{
"path": "/:category/:slug/images/:imageId?",
"method": "GET",
"script": "content/view.js"
}
]
}
Each object in the routes
array defines a single endpoint and has the following properties:
path
(string, required)
:
), followed by its name (e.g., :userId
). The name should use standard variable naming conventions.?
) to its name (e.g., :imageId?
).*
) as a wildcard to match the rest of a path.method
(string, optional)
GET
.GET
, POST
, PUT
, DELETE
, PATCH
. You can also use ALL
to match any method for a given path.script
(string, required)
box
folder. The .js
extension is optional."script": "api/users/get-profile"
will execute the file at web/my-app/box/api/users/get-profile.js
.When a route with dynamic parameters is matched, Gingee automatically parses the values from the URL and makes them available in your server script via the $g.request.params
object.
Example:
routes.json
:
{ "path": "/products/:productId/reviews/:reviewId", "script": "reviews/get.js" }
/my-app/products/abc-123/reviews/42
box/reviews/get.js
):
module.exports = async function() {
await gingee(async ($g) => {
const productId = $g.request.params.productId; // "abc-123"
const reviewId = $g.request.params.reviewId; // "42"
$g.response.send({
message: `Fetching review ${reviewId} for product ${productId}.`
});
});
};