diff --git a/README.md b/README.md index 4406b01..0326979 100644 --- a/README.md +++ b/README.md @@ -1,101 +1,59 @@ - - - Leptos Logo - +# Code Submission -# 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 -cargo install cargo-leptos --locked +This repository is not a generic template anymore; it is a working challenge server with specific code-handling behavior and operational configuration. + +## 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 -```bash -cargo leptos new --git https://github.com/leptos-rs/start-axum -``` +## Features -to generate a new project template. +### Code 1 -```bash -cd code_submission -``` +Code 1 is the timed buzz challenge. It accepts a `POST /event/buzz` request with: -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":""}' -``` - -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 { "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 -single test event: +- `delay_ms` must be a non-negative integer. +- `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":""}' +``` + +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": "" +} +``` + +### Test Code 1 with Node.js ```javascript async function main() { @@ -129,27 +206,20 @@ main().catch((error) => { }); ``` -When the server is live, a successful test event sends the configured TextBee -SMS to the configured recipients. When it is offline, it only logs the message. +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. -## 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 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 cargo leptos end-to-end ``` @@ -158,21 +228,24 @@ cargo leptos end-to-end cargo leptos end-to-end --release ``` -Cargo-leptos uses Playwright as the end-to-end test tool. -Tests are located in end2end/tests directory. +Cargo-leptos uses Playwright for browser tests and the test files are under `end2end/tests`. -## Executing a Server on a Remote Machine Without the Toolchain -After running a `cargo leptos build --release` the minimum files needed are: +## Remote deployment without the Rust toolchain -1. The server binary located in `target/server/release` -2. The `site` directory and all files within located in `target/site` +After running `cargo leptos build --release`, the minimum files needed are: + +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 code_submission site/ ``` -Set the following environment variables (updating for your project as needed): + +Set the appropriate environment variables before starting the binary: + ```sh export LEPTOS_OUTPUT_NAME="code_submission" 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_RELOAD_PORT="3001" ``` -Finally, run the server binary. + +Then run the server binary. ## 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.