Theme
Lesson 02 — Typed RPC and desktop/core separation
Outcome
Make a tiny typed request from a client to the Go core, such as GetServerInfo, without exposing filesystem/process power to the renderer.
Why this comes now
Before product behavior, prove the most important ownership boundary. Once UI code starts directly reading files or spawning commands, extracting that logic later is painful.
Understand
The RPC API is not remote database access. Mutations will eventually be domain commands. For now one read-only health/version method is enough. Protobuf gives one contract source and generated types; Connect works over normal HTTP and supports Go and web clients.
Electron main owns starting the core and handing the renderer a narrow connection configuration. The renderer remains unprivileged.
Build the real project
- Define a minimal
forge.v1.SystemService/GetServerInfoprotobuf message/service. - Configure Buf/code generation.
- Implement the Connect handler in Go.
- Generate the TypeScript client.
- From a tiny renderer/test client, show core version/status.
- Bind the core to loopback only and add a random per-launch/session credential before exposing command APIs.
Completion gate
Generated Go and TS code comes from one schema. A round trip succeeds. Renderer code contains no child_process, filesystem, or arbitrary Electron IPC command runner.
Pitfalls to avoid
Do not design 50 RPCs now. Do not hand-maintain duplicate DTOs. Do not add a generic ExecuteCommand(string) endpoint.
References
Required: Connect for Go, Connect for Web, Buf. Read also docs/architecture/RPC_AND_APP_BOUNDARY.md.
Checkpoint
Advance to Lesson 03 only after you can draw the renderer → RPC → application/core boundary from memory.