Typing and Editing for Learners and Teachers
A composition classroom: Writers draft without paste-cheating, Editors review and redraft, Observers watch, Administrators run a Facility (school), a Superintendent runs several Facilities. Blocks are classes.
PHP 8 + MariaDB (InnoDB) + PDO. Object pages import only the modules they use ($import = ['auth','writ']).
- Clone into the web folder (
/srv/www/99/webdiror similar). - Create a MariaDB database and user.
- Open
install.php. Database host should be127.0.0.1(TCP), notlocalhost(Unix socket). - Host setting is scheme-less:
write.pink,99.example.org, orexample.org/99. The app always useshttps://. - That creates a Superintendent. Create a Facility, then an Administrator.
- Mail, SMTP password, host, OAuth keys, and the update stream live in
config.php— SysAdmin work, not the in-app Admin. Superintendents cannot change those from the web.
Walk-in Superintendent recovery: set allow_create_super to true in config, open install.php, then set it false again.
- CLI:
php bin/update.phporbash bin/pw99-update - Admin / Superintendent locker: Update app
- Pulls the GitHub branch named in
config.phpasstream(never overwritesconfig.php), then runs SQL migrations. - If
streamis missing, oldergithub_branchstill works. The namemainis treated asmaster.
Two branches. stream is SysAdmin-only. Edit config.php. There is no in-app control.
| stream | What it is |
|---|---|
master |
Published line. Default. |
developer |
In-progress work. Point a box here to follow that branch. |
Empty id or secret in config.php hides that button. Callback for both providers is https://{host}/oauth.php (the same host value as in config, with https:// in front).
| Provider | Where to get the keys | What to paste |
|---|---|---|
Google Cloud credentials — create an OAuth client ID, application type Web application. Authorized redirect URI: https://{host}/oauth.php |
oauth.google.id and oauth.google.secret |
|
| GitHub | GitHub Developer settings — OAuth Apps → New OAuth App. Authorization callback URL: https://{host}/oauth.php |
oauth.github.id and oauth.github.secret |
'oauth' => [
'google' => ['id' => '….apps.googleusercontent.com', 'secret' => '…'],
'github' => ['id' => 'Ov…', 'secret' => '…'],
],The mysqli-era tree and sql/legacy-lift.sql live on the legacy history. Read that README. Import the dump into an empty database, then php bin/update.php on master (same lift in PHP).
| Role | Seat |
|---|---|
| Writer | Student |
| Observer | Parent / tutor |
| Editor | Teacher |
| Supervisor | Facility staff |
| Admin | One Facility |
| Superintendent | Many Facilities; password reset is in-person only |
- Writs, Assignments (writ + memo instructions), Tests (MC / fill-in / short answer / T-F)
- Fill-in:
||is OR;|&is AND/OR (either or both). No exclusive AND. - Redraft: editor version becomes the writer's next start.
draftsandredraftsJSON history. Show history or gray no history. - Note → Memo; Memo → Assignment.
- Lost-password email (Admin and below). TOTP authenticator. Passkeys. After passkey or Google / GitHub, Authenticator can Remember this machine for 30 days; password login always asks for the code.
- Google and GitHub login (SysAdmin
oauthkeys in config). Create or link. Authenticator and passkeys still apply after a social login. - In-app + email notification checkboxes in the Locker. Acknowledge deletes the notice.
PinkWrite 88 typing practice ships in 88/.
GPLv3