wren/val Public Public: anyone can read this; nobody can change it.

forked from benjivers/val

workbenchthis machine
Files 16611dd34ec2ea73a39a2dece0010023cace015e
1
# Working on this app
2
3
You are one of the crew on this repository. The forge runs the app for you:
4
production follows the default branch, and every pull you open gets a
5
preview at its own address, deployed from your branch as you push.
6
7
## The rules
8
9
- Work on the branch you were given. You cannot move the default branch;
10
  a person merges your pull once it is reviewed.
11
- Keep state under `FORGE_APP_DATA`. Never write elsewhere at runtime.
12
- Run `bun test` before you push. It is the check the pull shows, and every
13
  behaviour you add gets a test that would fail without it.
14
- `src/tty.ts` is the app's terminal interface. The exact command that
15
  reaches it is `FORGE_APP_SSH` at runtime; print that verbatim wherever the
16
  app tells people how to connect. Keep it working and keep it useful: what
17
  a person can do on the web page they should be able to do here too.
18
- Keep it dependency-free unless a dependency is clearly worth it, and say
19
  why in the pull. A dependency is code you now maintain.
20
- When you are done, push and stop. Your last message becomes the pull's
21
  description: say what changed, what you chose not to do, and what to look
22
  at in the preview.
23
24
## The bar
25
26
- Shape: small modules named after one concept, plain data in and out. When
27
  `src/server.ts` stops fitting in one read, split it — `src/db.ts` for
28
  the schema and queries, `src/pages/<page>.ts` for rendering,
29
  `src/routes.ts` for the table of paths — and keep the pattern you find.
30
- Security: every input is validated at the boundary and every output is
31
  escaped; every response carries the security floor in `src/server.ts`
32
  (keep it, extend it); a POST that is not same-origin is refused; secrets
33
  come from the environment, never the repository; no `eval`, no shell
34
  built from user text; a private thing needs a session in an HttpOnly cookie.
35
  Every request body is capped by the bytes actually read (`readBody` in
36
  `src/server.ts`) — never by a Content-Length, which a chunked request does
37
  not have and a lie does not honour. `HEAD` answers like `GET`.
38
  An app with an owner or admin is never claimed by whoever visits first:
39
  the first sign-in needs a secret only the operator holds — a password from
40
  the environment, or a one-time token printed to the run log and the app's
41
  terminal — and a generated password is shown there once, never on a page.
42
- Secrets come from the environment: the app's Settings → Environment
43
  (write-only), read at start-up; never the repository.
44
- Speed: the first paint is server-rendered HTML; JavaScript is small, in
45
  files under `static/` named by content and cached for a year; no layout
46
  shift; the common request answers in milliseconds; work that can wait is
47
  done after the response.
48
- A phone is a first-class client: the page works at 360px wide with no
49
  horizontal scroll, every control is at least 44px on a side, and the
50
  keyboard reaches everything a mouse does.
51
- Finish: the app boots, `/` answers, the README says how to use it and
52
  what is real versus simulated, `forge.json` says how to run it.
↑↓ navigate ↵ open esc close
↑↓ navigate ↵ open esc close

Keyboard shortcuts