- Not a JS/Rust monorepo: the Rust workspace only contains
apps/server; the frontend is a standalone pnpm project inapps/clientwith its own lockfile. - Backend entrypoint:
apps/server/src/main.rs— wires modules viasword::Application:auth,authz,banks,courses,users,quizzes,snapshots,shared,attempts. - Frontend shell:
apps/client/src/routes/+layout.svelte— installs TanStack Query provider and Axios interceptors. SSR is disabled in+layout.ts. - Real-time: Socket.IO server at
/attemptsnamespace (events:attempts:new-submit,attempts:new-attempt,attempts:warning). Client inapps/client/src/lib/shared/socket/attempts.socket.ts.
- Preferred local workflow is Docker-first.
make runstarts the full stack fromcompose.yml;make detachruns in background. - First-time setup:
make setup(deletes clientnode_modules, runscorepack pnpm install, rebuilds containers). - Repo-wide formatting/lint:
make fmt/make lint(runs both backend and frontend). - Focused backend from root:
cargo fmt --all,cargo clippy --workspace --all-targets --all-features -- -D warnings,cargo test -p server. - Focused frontend from
apps/client:corepack pnpm run lint,corepack pnpm run check,corepack pnpm run build. - CI does not run frontend tests (none exist). Client CI:
lint+check. Server CI:fmt --check+clippy+test. - DB migration:
make migration name=<name>(runssqlx migrate add).make clean-dbdrops and recreates the public schema (destructive). make machetechecks for unused Rust dependencies.- Package management:
make npmi pkg=<name>,make npmu pkg=<name>,make npmci.
- Root
.envis loaded bymake,compose.yml, and Vite (apps/client/vite.config.tsusesenvDir: "../../"). There is noapps/client/.env. - Local entrypoint: nginx container on port
80. Nginx proxies/→ client:5173,/api/→ server:8000. - Frontend Axios
baseURL: "/api"— preserve this proxy path unless intentionally changing nginx wiring. - Server runs SQL migrations automatically in
Database::new()fromapps/server/config/migrations. - Server dev container entrypoint (
apps/server/config/scripts/entrypoint.sh) runscargo watchonly — no VPN/WireGuard setup locally. - Compose services:
server,nginx,postgres,client,ldap,ldap-ui. LDAP services are for auth integration;ldap-uiis on port8080.
- Backend features:
apps/server/src/<feature>/withcontroller,service,repository, and optionalpolicy/dtos/entity. Start there. - Frontend features:
apps/client/src/lib/features/*(attempts, banks, courses, quizzes, users). Route files are thin wrappers. - Auth/session:
apps/client/src/lib/auth/service.tsandapps/client/src/lib/shared/http/api.interceptors.ts. Protected-route redirect:apps/client/src/routes/(protected)/+layout.ts. - Anti-cheat system:
apps/client/src/lib/attempts/services/anti-cheat.service.svelte.ts— blocks context menu, copy, search, screenshot, alt-tab. Warnings broadcast via Socket.IO. - API docs:
.docs/endpoints/contains per-resource markdown docs (auth, users, courses, banks, quizzes, attempts).
- Frontend formatting from root
.prettierrc: tabs, no semicolons,printWidth: 100, double quotes, Tailwind class sorting viaprettier-plugin-tailwindcssusingapps/client/src/routes/layout.css. - Frontend uses Svelte 5 runes (
$state,$derived) — not legacy store patterns. Match existing style. - Schema validation:
valibot(not zod or yup). - Key frontend deps:
@tanstack/svelte-queryv6,axios,socket.io-client,marked+dompurify(markdown),katex(math),lucide-svelte(icons),svelte-sonner(toasts),@formisch/svelte(forms),runed(runes utilities).
- No implementation leaks. Visible text must never reference internal architecture, contracts, endpoints, policies, authorization roles, technical jargon, or development status.
- User-oriented copy only. Describe what the user can do, not how the system works.
- No generic kickers without context. Avoid meaningless section labels like "Flujo estudiante", "Gestion academica", "Curso", or "Quiz".
- Consistent language. Prefer "Crea y administra quizzes de este curso." over "Gestion de quizzes por curso: creacion, listado y acciones administrativas."
- Error messages should be actionable and in Spanish, but may reference HTTP status codes when helpful.
- Production images built via
ghcr-images.ymlCI workflow → GHCR (ramtun-server,ramtun-client). - K8s deployer:
make deployer cmd=<deploy|db|sh|kubectl> [args=...]— builds and runs a container with kubectl + WireGuard. Uses.env.prodand~/.kube. - K8s manifests in
config/deployer/k8s/: server, client, postgres (CloudNativePG), ingress atramtun.inf.uct.cl. compose.prod.ymlis a simplified production compose (no nginx — client Dockerfile prod stage includes it).