[OCaml] High Intensity Training Online
1
(** Persistence port. A pure module type: no database or web framework.
2
3
Identity lives here rather than in the core, which carries none — a routine,
4
a stored workout, or a trainee needs a name only once something has to
5
remember it.
6
7
Every operation is scoped to a {!Trainee.id}. There is no server-wide state:
8
the active routine and the workout in progress belong to a trainee and are
9
stored, so nothing is lost across a restart and no two trainees share a
10
slot. *)
11
12
type routine_id = private string
13
type workout_id = private string
14
15
val routine_id : string -> routine_id
16
val workout_id : string -> workout_id
17
18
type record = { id : workout_id; workout : Evidence.Workout.t }
19
(** A stored workout. It already knows its prescription, its timestamps, and the
20
basis on which it was begun. *)
21
22
type app_feedback_id = private string
23
24
val app_feedback_id : string -> app_feedback_id
25
val app_feedback_id_to_string : app_feedback_id -> string
26
27
type app_feedback = {
28
feedback_id : app_feedback_id;
29
author : string;
30
contributions : int;
31
submitted_at : Recovery.timestamp;
32
message : string;
33
upvotes : int;
34
viewer_upvoted : bool;
35
viewer_owns : bool;
36
}
37
(** A ranked application comment with viewer vote and ownership state. *)
38
39
(** Effects run in Lwt: an adapter may talk to a database. *)
40
module type S = sig
41
type t
42
43
(** {2 Accounts} *)
44
45
val create_trainee :
46
t ->
47
username:Trainee.username ->
48
credential:Trainee.credential ->
49
(Trainee.t, [ `Username_taken ]) result Lwt.t
50
51
val find_trainee_by_username : t -> Trainee.username -> Trainee.t option Lwt.t
52
val find_trainee : t -> Trainee.id -> Trainee.t option Lwt.t
53
54
val update_username :
55
t ->
56
Trainee.id ->
57
Trainee.username ->
58
(Trainee.t, [ `Username_taken ]) result Lwt.t
59
(** Rename the account. [`Username_taken] if another account holds the name.
60
The trainee's own current name is accepted as a no-op. Returns the updated
61
trainee on success. *)
62
63
val update_credential :
64
t -> Trainee.id -> Trainee.credential -> Trainee.t option Lwt.t
65
(** Replace the account's password verifier. [None] if unknown. *)
66
67
(** {2 Catalog}
68
69
Shared, not trainee-scoped. *)
70
71
val list_routines : t -> (routine_id * Prescription.Routine.t) list
72
val find_routine : t -> routine_id -> Prescription.Routine.t option
73
74
(** {2 Per-trainee selection and workout in progress} *)
75
76
val active_routine : t -> Trainee.id -> routine_id option Lwt.t
77
val set_active_routine : t -> Trainee.id -> routine_id -> unit Lwt.t
78
val in_progress : t -> Trainee.id -> Evidence.Workout.t option Lwt.t
79
80
val set_in_progress :
81
t -> Trainee.id -> Evidence.Workout.t option -> unit Lwt.t
82
(** [None] clears the slot. *)
83
84
(** {2 History} *)
85
86
val finish_workout : t -> Trainee.id -> Evidence.Workout.t -> record Lwt.t
87
(** Store a finished workout and clear the in-progress slot as one unit. An
88
adapter with transactions performs both in a single transaction, so a
89
workout is never both saved to history and still shown as in progress. *)
90
91
val find : t -> Trainee.id -> workout_id -> record option Lwt.t
92
93
val replace : t -> Trainee.id -> record -> bool Lwt.t
94
(** Replace an existing record by identity. *)
95
96
val log : t -> Trainee.id -> Evidence.Log.t Lwt.t
97
(** The stored log — the only source of evidence. *)
98
99
val history : t -> Trainee.id -> record list Lwt.t
100
(** Most recent first. *)
101
102
(** {2 Subjective feedback} *)
103
104
val save_feedback : t -> Trainee.id -> Evidence.Feedback.t -> unit Lwt.t
105
(** Store a subjective feedback report. Feedback is a standalone observation,
106
not tied to a workout: a trainee may report it at any time. *)
107
108
val feedback : t -> Trainee.id -> Evidence.Feedback.t list Lwt.t
109
(** Stored feedback reports, most recent first. *)
110
111
val save_app_feedback :
112
t ->
113
Trainee.id ->
114
submitted_at:Recovery.timestamp ->
115
message:string ->
116
app_feedback Lwt.t
117
(** Store a freeform application feedback report and return its identity. *)
118
119
val app_feedback : t -> viewer:Trainee.id -> app_feedback list Lwt.t
120
(** Return all reports, ranked by upvotes, with the viewer's vote state. *)
121
122
val upvote_app_feedback :
123
t -> voter:Trainee.id -> app_feedback_id -> bool Lwt.t
124
(** Add one vote from another trainee. [false] means no vote was added. *)
125
126
val update_app_feedback :
127
t -> author:Trainee.id -> app_feedback_id -> message:string -> bool Lwt.t
128
(** Update a report only when [author] owns it. *)
129
130
val delete_app_feedback :
131
t -> author:Trainee.id -> app_feedback_id -> bool Lwt.t
132
(** Remove a report and its votes only when [author] owns it. *)
133
end
134