Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 14 additions & 5 deletions ainigma-backend/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,24 @@ edition = "2024"
ainigma = { path = "../ainigma" }

# and any other dependencies you need:
hyper = "1.6.0"
axum = "0.8.4"
tokio = { version = "1", features = ["full"] }
uuid = { version = "1.17.0", features = ["v7", "serde"] }
tokio = { version = "1", features = ["macros", "rt-multi-thread", "fs"] }
uuid = { version = "1.17.0", features = ["v4", "v7", "serde"] }
serde = { version = "1.0.211", features = ["derive"] }
serde_json = "1"
tower = "0.5.2"
sqlx = { version = "0.8.6", features = ["postgres", "runtime-tokio-rustls"] }
sqlx = { version = "0.8.6", features = ["postgres", "uuid", "runtime-tokio-rustls"] }
thiserror = "2"
lazy_static = "1.5.0"
regex = "1.11.1"
tracing = "0.1.41"
tracing-subscriber = { version = "0.3.19", features = ["env-filter", "fmt"]}
chrono = "0.4.41"
anyhow = "1.0.98"
mime_guess = "2.0.5"
tokio-util = "0.7.16"

[dev-dependencies]
reqwest = { version = "0.12.19", features = ["json"] }
tokio = { version = "1", features = ["full"] }
tokio = { version = "1", features = ["macros", "rt-multi-thread", "fs"] }
httpc-test = "0.1.1"
20 changes: 11 additions & 9 deletions ainigma-backend/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,12 @@ Other things they need to take for backend to work
## Software

Sqlx - Database
Smithy - Generating code for backend

## Serverside structure

```
/srv/ainigma/data/
/courses/
Index file (index for quick course lookup and listing)
/<course_id>/ (or name)
config.toml (defined name for pathing)
/<category>/ (name)
Expand All @@ -39,10 +37,12 @@ Smithy - Generating code for backend
courses (1) ── (many) categories (1) ── (many) tasks
users (1) ── (many) user_task_progress (many) ── (1) tasks

## workflow
## Workflow

```
[Client]
|
|-- Request for structures course, category (static response figured at server start) -->
|-- Request (uuid, task_id, course_id) -->
|
[Server]
Expand All @@ -53,8 +53,9 @@ users (1) ── (many) user_task_progress (many) ── (1) tasks
| |-- Generate flags
| |-- Build task using course config
| |-- Save built task
| |-- Add Correct flag / answer to database
|-- Return task data -->
|-- Add Correct flag / answer to database
|
[Client receives task and starts solving]
[Client]
|
Expand All @@ -67,15 +68,16 @@ users (1) ── (many) user_task_progress (many) ── (1) tasks
|-- No: send feedback
|
[Client] receives feedback

```
## Questions

- Category no identifier and task has String

- Course secret storage?
- Changes only when server down? (configuration checked at start and expected to be correct during runtime)
or updates? (updates to config during server runtime, checked in runtime with functionality locked during update process )
- Database and authentication?


## Feedback

- No support for v7 uuid in postgre only v4
- New build function that takes a uuid, and just takes module and task_id
- config catogories.tasks.build path made obsolete in backend - backend always knows what task to process

107 changes: 0 additions & 107 deletions ainigma-backend/backend.rs

This file was deleted.

46 changes: 34 additions & 12 deletions ainigma-backend/migrations/0001_ainigma.sql
Original file line number Diff line number Diff line change
Expand Up @@ -2,39 +2,61 @@ CREATE EXTENSION IF NOT EXISTS "uuid-ossp";

CREATE TABLE users (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
email VARCHAR UNIQUE NOT NULL,
created_at TIMESTAMPTZ DEFAULT now()
);

CREATE TABLE courses (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
title VARCHAR NOT NULL,
name VARCHAR NOT NULL,
description TEXT,
created_at TIMESTAMPTZ DEFAULT now()
);

CREATE TABLE categories (
id SERIAL PRIMARY KEY,
course_id UUID NOT NULL REFERENCES courses(id) ON DELETE CASCADE,
name VARCHAR NOT NULL,
number INTEGER
number INTEGER NOT NULL,
PRIMARY KEY (course_id, name)
);

CREATE TABLE tasks (
id SERIAL PRIMARY KEY,
category_id INTEGER NOT NULL REFERENCES categories(id) ON DELETE CASCADE,
title VARCHAR NOT NULL,
id VARCHAR NOT NULL,
course_id UUID NOT NULL,
category_name VARCHAR NOT NULL,
name VARCHAR NOT NULL,
description TEXT,
points INTEGER DEFAULT 1,
created_at TIMESTAMPTZ DEFAULT now()
created_at TIMESTAMPTZ DEFAULT now(),
PRIMARY KEY (course_id, category_name, id),
FOREIGN KEY (course_id, category_name) REFERENCES categories(course_id, name) ON DELETE CASCADE
);

CREATE TABLE task_stages (
id VARCHAR NOT NULL, -- stage ID (e.g., "task001A")
course_id UUID NOT NULL,
category_name VARCHAR NOT NULL,
task_id VARCHAR NOT NULL, -- parent task ID
name VARCHAR NOT NULL,
description TEXT,
weight INTEGER DEFAULT 1,
flag JSONB, -- metadata like { kind: "user_derived" }
created_at TIMESTAMPTZ DEFAULT now(),
PRIMARY KEY (course_id, category_name, task_id, id),
FOREIGN KEY (course_id, category_name, task_id) REFERENCES tasks(course_id, category_name, id) ON DELETE CASCADE
);


CREATE TABLE user_task_progress (
id SERIAL PRIMARY KEY,
CREATE TABLE user_stage_progress (
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
task_id INTEGER NOT NULL REFERENCES tasks(id) ON DELETE CASCADE,
course_id UUID NOT NULL,
category_name VARCHAR NOT NULL,
task_id VARCHAR NOT NULL,
stage_id VARCHAR NOT NULL, -- stage ID
completed_at TIMESTAMPTZ,
completed BOOLEAN NOT NULL DEFAULT FALSE,
score INTEGER,
UNIQUE (user_id, task_id)
PRIMARY KEY (user_id, course_id, category_name, task_id, stage_id),
FOREIGN KEY (course_id, category_name, task_id, stage_id)
REFERENCES task_stages(course_id, category_name, task_id, id)
ON DELETE CASCADE
);
9 changes: 9 additions & 0 deletions ainigma-backend/model.smithy
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,18 @@ structure UserLoginOutput {
}

operation ListCourses{
output: ListCoursesOutput,
}
structure ListCoursesOutput {
courses: Vec<Course>
}

structure Course{
name: String
id: Uuid
}


operation GetCourseConfig{
input: CourseConfigInput,
output: CourseConfigOutput
Expand Down
Loading