SERVER / FILE MODEL
Six responsibilities, one request path
main.dowe activates the server. Endpoint modules map HTTP methods and paths, middleware controls access, handlers own the HTTP boundary, functions own reusable logic, and config modules expose server-only resources.
File or declaration | Owns | What belongs there |
|---|---|---|
No dataThere are no records to display | ||
PROJECT SHAPE
Organize the backend by responsibility
This tree is recommended because it makes security and ownership visible. Imported modules are classified by their declarations, not by their folders, but new backend source should stay under server.
main.dowe
.env.example
.env
server/
endpoints.dowe
handlers/
middlewares/
config/
services/
repositories/
providers/
tasks/
utils/
types/
entities/
seeders/
migrations/Boundary | Rule |
|---|---|
No dataThere are no records to display | |
CONNECTED EXAMPLE
Follow one request through the backend
These six files expose GET /api/blogs. The HTTP boundary stays thin, the service coordinates the use case, and the repository is the only function that reads Database.
1 / main.dowe
Activate the imported endpoint graph
The root file chooses the server port and connects the endpoint declaration that owns the HTTP routes.
import ApiRoutes from "@/server/endpoints"
main
server port:8080
endpoints:ApiRoutes2 / server/endpoints.dowe
Map the method and path
The endpoints declaration joins a URL to the handler imported from the handlers folder.
import listBlogs from "@/server/handlers/blogs-handler"
endpoints ApiRoutes
group path:"/api/blogs"
get path:"" handler:listBlogs3 / server/handlers/blogs-handler.dowe
Choose the HTTP response
The handler is the HTTP boundary: it calls the use case and serializes the value as JSON.
import listBlogsService from "@/server/services/blogs-service"
handler listBlogs
listBlogsService blogs
return json:{ ok:true data:blogs }4 / server/services/blogs-service.dowe
Coordinate the use case
The service connects the handler to reusable business logic without returning an HTTP response.
import listBlogsRepository from "@/server/repositories/blogs-repository"
fn listBlogsService
listBlogsRepository blogs
return value:blogs5 / server/repositories/blogs-repository.dowe
Own the Database operation
The repository imports the configured handle, executes the query, and returns a value to the service.
import AppDb from "@/server/config/database"
fn listBlogsRepository
query blogs conn:AppDb.list table:"blogs"
return value:blogs6 / server/config/database.dowe
Export the server-only connection
Configuration owns credentials and connection details. Other server modules import the handle instead of rebuilding it.
database AppDb:
provider:"dowe"
host:env.DATABASE_HOST
port:env.DATABASE_PORT
account:env.DATABASE_ACCOUNT
secret:env.DATABASE_SECRET
name:env.DATABASE_NAME
entities:[]
seeders:[]MIDDLEWARE BOUNDARY
Authorize before business logic runs
Middleware belongs on a group, HTTP method, or WebSocket. It either calls next, optionally adding server-only context, or returns a response that prevents the handler from running.
1 / server/middlewares/require-bearer.dowe
Stop unauthorized requests
This middleware validates the bearer token, adds the subject to trusted request context, or returns a 401 before the handler runs.
middleware requireBearer
bearer token value:req.header.Authorization
jwt verified secret:env.JWT_SECRET algorithm:"HS256" token:token
if verified.valid
next context:{ auth:{ subject:verified.claims.sub } }
return status:401 json:{ ok:false error:"Unauthorized" }2 / server/endpoints.dowe
Attach the policy to a route
The endpoint declares the middleware on the method, so only this protected request passes through requireBearer.
import requireBearer from "@/server/middlewares/require-bearer"
import createBlog from "@/server/handlers/blogs-handler"
endpoints ApiRoutes
group path:"/api/blogs"
post path:"" handler:createBlog middleware:[requireBearer]DECISION GUIDE
Create the file that owns the authority
Keep the HTTP edge, use-case coordination, data access, integrations, and shared resources separate so security decisions remain visible.
Change | Owner | Where to put it |
|---|---|---|
No dataThere are no records to display | ||