update readme

This commit is contained in:
2026-10-20 11:20:55 -05:00
parent e869a7addd
commit 96029d62b4
+188 -114
View File
@@ -1,101 +1,59 @@
<picture> # Code Submission
<source srcset="https://raw.githubusercontent.com/leptos-rs/leptos/main/docs/logos/Leptos_logo_Solid_White.svg" media="(prefers-color-scheme: dark)">
<img src="https://raw.githubusercontent.com/leptos-rs/leptos/main/docs/logos/Leptos_logo_RGB.svg" alt="Leptos Logo">
</picture>
# Leptos Axum Starter Template This project is a Leptos + Axum app for a multi-step code submission challenge. It exposes a small web UI where users enter a code, accepts challenge submissions for valid codes, and can toggle the server between offline and live mode for SMS-driven challenge flow testing.
This is a template for use with the [Leptos](https://github.com/leptos-rs/leptos) web framework and the [cargo-leptos](https://github.com/akesson/cargo-leptos) tool using [Axum](https://github.com/tokio-rs/axum). ## Overview
## Creating your template repo The app supports:
If you don't have `cargo-leptos` installed you can install it with - A home page for entering challenge codes.
- A `/submit/:code` route that validates supported codes.
- A `/manage` page to toggle the server between live and offline states.
- A `/history` page for successful submission records.
- A protected `POST /event/buzz` endpoint for challenge code 1, which validates a secret and timing window.
- TextBee SMS notifications when the server is live.
```bash This repository is not a generic template anymore; it is a working challenge server with specific code-handling behavior and operational configuration.
cargo install cargo-leptos --locked
## Project structure
```text
.
├── Cargo.toml
├── README.md
├── dev.env
├── LICENSE
├── end2end/
│ ├── package.json
│ ├── playwright.config.ts
│ └── tests/
├── public/
│ ├── challenge3.txt
│ ├── challenge3_annotated.txt
│ └── favicon.ico
├── src/
│ ├── app.rs
│ ├── lib.rs
│ ├── main.rs
│ ├── manage.rs
│ ├── secrets.rs
│ └── codes/
│ ├── code1.rs
│ ├── code2.rs
│ ├── code5.rs
│ ├── history.rs
│ └── mod.rs
├── style/
│ └── main.scss
└── target/
``` ```
Then run ## Features
```bash
cargo leptos new --git https://github.com/leptos-rs/start-axum
```
to generate a new project template. ### Code 1
```bash Code 1 is the timed buzz challenge. It accepts a `POST /event/buzz` request with:
cd code_submission
```
to go to your newly created project.
Feel free to explore the project structure, but the best place to start with your application code is in `src/app.rs`.
Additionally, Cargo.toml may need updating as new versions of the dependencies are released, especially if things are not working after a `cargo update`.
## Running your project
```bash
cargo leptos watch
```
Copy `dev.env` to `.env`, then replace the placeholder with a unique secret
before starting the server. The `.env` file is loaded automatically at startup
and is ignored by Git. Startup validates the required settings and stops with a
clear error if any are missing or malformed. `DEV_SECRET_KEY` authorizes server
status changes and submission-history access:
```powershell
Copy-Item dev.env .env
```
You can also provide `DEV_SECRET_KEY` through the process environment. Do not
commit secrets or expose them in client-side code.
Set `PROD=true` to make the server start in the live state. Truthy values are
`1`, `true`, `yes`, and `on` (case-insensitive); an absent or other value starts
the server offline.
Code 1 sends an SMS through TextBee when the server is live. Set
`TEXTBEE_API_KEY`, `RECIPIENT_SELF`, `RECIPIENT_1`, and `RECIPIENT_2` (each a
single E.164 number) in `.env`; `TEXTBEE_DEVICE_ID` is optional and selects a
specific paired device. When live, code 1 sends a notification to self, the
congratulations message to recipients 1 and 2, then `CHALLENGE_1_FIRST` to
recipient 1 and `CHALLENGE_1_SECOND` to recipient 2. The latter two are sent
literally as written. When offline, the planned messages are logged instead.
TextBee acceptance means a message was queued, not necessarily delivered.
Code 2 uses the former manual code value (`QJ4EAN`). Code values are case
insensitive. On successful submission, code 2 sends a notification to
`RECIPIENT_SELF` while the server is live (and logs the notification instead
while offline). The result page displays `NEXT_STEP_TEXT` from
`src/codes/code2.rs`; replace its TODO text with the next step when ready.
Code 5 uses the code value defined in `src/codes/code5.rs`. A successful
submission sends a notification to `RECIPIENT_SELF` while the server is live
(and logs the notification instead while offline), and displays the completion
message without providing a download.
The robot submits code 1 with `POST /event/buzz` and a JSON body containing
`delay_ms` (a non-negative integer) and `secret` (the value of `CODE1_SECRET`).
The server subtracts the target delay of 6430 ms from `delay_ms` to calculate
the signed buzz delta. Deltas outside the inclusive range -500 to +500 ms are
logged and ignored; the endpoint returns HTTP `200` and does not record the
submission or send/log the submission actions. Accepted submissions return
HTTP `202`. Correctly timed buzzes are only accepted between 11:00 AM and
1:30 PM, inclusive, in the `America/Chicago` timezone. Requests outside that
window are logged and return HTTP `200` without running submission actions.
Set `CODE1_SECRET` to a unique random secret of at least 32 bytes in
`.env`. For example, with the server running locally:
```sh
curl.exe -X POST http://127.0.0.1:3000/event/buzz -H "Content-Type: application/json" -d '{"delay_ms":6388,"secret":"<your CODE1_SECRET value>"}'
```
The server calculates `6388 - 6430 = -42` ms for the congratulations message.
A valid request returns HTTP `202`.
### Test code1 with Postman
Create a `POST` request to `http://127.0.0.1:3000/event/buzz`, select **Body >
raw > JSON**, and send:
```json ```json
{ {
"delay_ms": 6388, "delay_ms": 6388,
@@ -103,10 +61,129 @@ raw > JSON**, and send:
} }
``` ```
### Test code1 with Node.js Behavior:
With the server running and `CODE1_SECRET` set in your shell, this sends a - `delay_ms` must be a non-negative integer.
single test event: - `secret` must match `CODE1_SECRET` exactly.
- The request is only accepted in the `America/Chicago` window from 11:00 AM to 1:30 PM inclusive.
- The server computes the signed delta from the target of `6430 ms`.
- Deltas outside the inclusive range `-500` to `+500` are rejected and ignored.
- Valid submissions return HTTP `202`.
- When live, the app sends SMS notifications via TextBee to the configured recipients.
- When offline, it logs the planned SMS actions instead.
The challenge text includes the literal strings `CHALLENGE_1_FIRST` and `CHALLENGE_1_SECOND`, which are sent to the configured recipients once the buzz is accepted.
### Code 2
The code value is `QJ4EAN` and is case-insensitive.
On successful submission:
- It records the success in the submission history.
- If the server is live, it sends a TextBee SMS to `RECIPIENT_SELF`.
- If the server is offline, it logs the notification instead.
### Code 5
The code value is `V7MK2P` and is case-insensitive.
On successful submission:
- It records the success in the submission history.
- If the server is live, it sends a TextBee SMS to `RECIPIENT_SELF`.
- If the server is offline, it logs the notification instead.
- It shows a completion message without providing a download.
## Getting started
### Prerequisites
You need Rust, the Leptos toolchain, and the project dependencies.
If you do not have `cargo-leptos` installed:
```bash
cargo install cargo-leptos --locked
```
If you need the additional tooling required by cargo-leptos:
```bash
rustup toolchain install nightly --allow-downgrade
rustup target add wasm32-unknown-unknown
cargo install cargo-generate
npm install -g sass
```
Then install the end-to-end test dependencies:
```bash
cd end2end
npm install
```
### Environment configuration
Copy the sample environment file to `.env` before starting the app:
```powershell
Copy-Item dev.env .env
```
The app loads `.env` automatically at startup and validates the required values. The expected settings are defined in `src/secrets.rs` and include:
- `DEV_SECRET_KEY` — required for admin actions such as toggling live/offline mode and accessing submission history.
- `TEXTBEE_API_KEY` — required for sending SMS via TextBee.
- `TEXTBEE_DEVICE_ID` — optional, selects a specific paired device.
- `RECIPIENT_SELF`, `RECIPIENT_1`, `RECIPIENT_2` — each must be a valid E.164 phone number.
- `CODE1_SECRET` — required and must be at least 32 bytes long.
- `PROD` — set to `true` to start the server in the live state. Truthy values are `1`, `true`, `yes`, and `on` (case-insensitive); any other value starts the server offline.
Do not commit secrets or expose them in client-side code.
### Run the app
```bash
cargo leptos watch
```
Then open the local app in your browser as directed by cargo-leptos.
## Management and admin flow
The app includes a status management page at `/manage`.
- It shows whether the server is currently live.
- It lets an operator toggle the server status.
- It requires the configured `DEV_SECRET_KEY` before changing state.
This is how the system can be transitioned between testing/offline and live challenge operation without exposing the settings publicly.
## Challenge testing
### Test Code 1 with curl
With the server running locally and `CODE1_SECRET` set in your shell:
```sh
curl.exe -X POST http://127.0.0.1:3000/event/buzz -H "Content-Type: application/json" -d '{"delay_ms":6388,"secret":"<your CODE1_SECRET value>"}'
```
The server calculates `6388 - 6430 = -42` ms, and a valid request returns HTTP `202`.
### Test Code 1 with Postman
Create a `POST` request to `http://127.0.0.1:3000/event/buzz`, select Body > raw > JSON, and send:
```json
{
"delay_ms": 6388,
"secret": "<your CODE1_SECRET value>"
}
```
### Test Code 1 with Node.js
```javascript ```javascript
async function main() { async function main() {
@@ -129,27 +206,20 @@ main().catch((error) => {
}); });
``` ```
When the server is live, a successful test event sends the configured TextBee When the server is live, a successful test event sends the configured TextBee SMS to the configured recipients. When it is offline, it logs the action instead.
SMS to the configured recipients. When it is offline, it only logs the message.
## Installing Additional Tools ## Build, test, and release
By default, `cargo-leptos` uses `nightly` Rust, `cargo-generate`, and `sass`. If you run into any trouble, you may need to install one or more of these tools. ### Compile for release
1. `rustup toolchain install nightly --allow-downgrade` - make sure you have Rust nightly
2. `rustup target add wasm32-unknown-unknown` - add the ability to compile Rust to WebAssembly
3. `cargo install cargo-generate` - install `cargo-generate` binary (should be installed automatically in future)
4. `npm install -g sass` - install `dart-sass` (should be optional in future
5. Run `npm install` in end2end subdirectory before test
## Compiling for Release
```bash ```bash
cargo leptos build --release cargo leptos build --release
``` ```
Will generate your server binary in target/release and your site package in target/site This will generate the server binary in `target/release` and the site bundle in `target/site`.
### End-to-end tests
## Testing Your Project
```bash ```bash
cargo leptos end-to-end cargo leptos end-to-end
``` ```
@@ -158,21 +228,24 @@ cargo leptos end-to-end
cargo leptos end-to-end --release cargo leptos end-to-end --release
``` ```
Cargo-leptos uses Playwright as the end-to-end test tool. Cargo-leptos uses Playwright for browser tests and the test files are under `end2end/tests`.
Tests are located in end2end/tests directory.
## Executing a Server on a Remote Machine Without the Toolchain ## Remote deployment without the Rust toolchain
After running a `cargo leptos build --release` the minimum files needed are:
1. The server binary located in `target/server/release` After running `cargo leptos build --release`, the minimum files needed are:
2. The `site` directory and all files within located in `target/site`
1. The server binary in `target/server/release`
2. The `site` directory and all files inside it in `target/site`
Copy these files to your remote server. The expected directory structure is:
Copy these files to your remote server. The directory structure should be:
```text ```text
code_submission code_submission
site/ site/
``` ```
Set the following environment variables (updating for your project as needed):
Set the appropriate environment variables before starting the binary:
```sh ```sh
export LEPTOS_OUTPUT_NAME="code_submission" export LEPTOS_OUTPUT_NAME="code_submission"
export LEPTOS_SITE_ROOT="site" export LEPTOS_SITE_ROOT="site"
@@ -180,8 +253,9 @@ export LEPTOS_SITE_PKG_DIR="pkg"
export LEPTOS_SITE_ADDR="0.0.0.0:3000" export LEPTOS_SITE_ADDR="0.0.0.0:3000"
export LEPTOS_RELOAD_PORT="3001" export LEPTOS_RELOAD_PORT="3001"
``` ```
Finally, run the server binary.
Then run the server binary.
## Licensing ## Licensing
This template itself is released under the Unlicense. You should replace the LICENSE for your own application with an appropriate license if you plan to release it publicly. This project is released under the repository's existing license. The default template license is present in `LICENSE`, and you should replace it with an appropriate license if you intend to distribute this project publicly.