Documents gerbeur, a small invite-only social platform for sharing links and
files. The repository holds three parts: the backend in api/, the
frontend in src/, and in shared/ whatever crosses the wire between them.
Every module is listed by path, so the list groups
them by part and layer.
Backend, in api/
An Oak server over SQLite answers the API and the WebSocket, and serves the
built frontend. api/main.ts builds the application and listens. A request
goes to a route, which parses it, calls services and answers. The services
hold the logic and every SQL query, read rows through the model, and reach
other sites only through remote/. Each folder holds one kind of module,
and each file is named after its domain.
routes/holds the HTTP API, one router per resource. Each router's page lists its endpoints, with their method and path, who may call them, and what they do;API.mdat the root sums them up, with the rule they all follow.middleware/holds what runs around the routes, which is auth, errors and the Open Graph tags.services/holds the logic and every SQL query, one module per domain.model/holds each table's row type, guard and mappers.validators/holds the guards of the request bodies.remote/is the only place that fetches from other sites, and itsproviders/build the previews of each kind of site.mail/renders each email, one template per email on a shared layout that takes every site style, its colors and fonts read from the themes' stylesheets, andservices/email-service.tssends them.lib/holds the helpers that belong to no layer.db/opens, creates and migrates the database, and cleans it up at startup.db/migrations/are applied in order, each once.config.tsreads the settings from the environment, andscripts/holds the icon generator.
Shared, in shared/
The types and constants both halves use sit here, one module per domain.
They are the API envelope, each domain's types and request bodies, the
socket protocol, the validation limits, the role permissions, and the page
paths and slugs (paths.ts, slug.ts) the client links with and the
server matches. shared/ imports nothing from either half. The server
sends Dates, and the client reads the same types through Wire<T>, where
every Date is an ISO string.
Beside it, locales/ holds one Lingui catalogue per language for the whole
app: the interface's messages, and the emails' that api/mail/i18n.ts
loads compiled. The interface writes its English in place (t, Trans)
and Lingui keys the message by it. A message with a named id, which every
email's is, along with the labels the interface shares with them, has its
English in locales/en.po alone and the code names only the id; the build
fails when a language lacks one.
Frontend, in src/
The React app is built with Vite and translated with Lingui. main.tsx
mounts it, App.tsx holds the providers and the route table, and i18n.ts
sets the language. A page reads the API and the socket through contexts and
hooks, and draws with components, while utils hold what isn't React at all.
pages/holds one component per route, each naming its route, and the two guards that keep routes to signed-in or signed-out visitors.config/holds the settings read at startup.contexts/holds, for each domain, aFooContextwith its state and theFooProviderthat fills it.hooks/holds every hook, andcomponents/only components.utils/holds every module that isn't React.
Every layer but pages/ and config/ is split into the same domains (auth,
category, chat, comment, dump, editor, feed, form, layout, player, playlist,
profile, social, theme, ws, and shared for what belongs to no one domain), so
the chat lives in components/chat/, contexts/chat/, hooks/chat/ and
utils/chat/.