Azure in Chennai, one TypeScript codebase
One codebase builds the web app and the Android app. The API and records run on Azure's basic and pay-per-use tiers in South India (Chennai), with backups in Central India (Pune). The data model shows every Release 1 table and the requirements it serves.
| Setting | Release 1 | Traced to |
|---|---|---|
| Service and tier | Azure SQL Database Basic (5 DTU, 2 GB) in South India; moves to S0 when load or size requires. | E01-F06-US12E01-F12-NFR01E01-F12-NFR06 |
| Sign-in | Entra-only: no SQL passwords; the API connects with a managed identity. | E01-F06-US11E01-F06-US12 |
| Row-level security | Every query filters on franchise and branch keys; coaches and nutritionists see their own branches, the Executive Coach and App Admin see all; the libraries are network-wide. | E01-F02-US02E03-F03-US02E01-F11-NFR01 |
| Encryption | Encrypted at rest; health declaration answers are encrypted and kept out of logs. | E01-F11-NFR01E12-F01-US03E01-F11-NFR04 |
| Backups and recovery | Point-in-time restore (7 days) and weekly long-term backups, geo-redundant to Central India (Pune); a restore drill before go-live. | E01-F10-NFR04E01-F10-NFR05E15-F05-US05 |
| Schema changes | Migration files only, applied by the pipeline, which opens the firewall to its own address only for the run. | E01-F07-US04 |
| Auditing | Every change, and staff views of nutrition data and meal photos, recorded in audit_event; database audit logs go to write-once storage. | E01-F05-US01E01-F05-US02E01-F11-NFR07 |
| Meal photo storage | Private container; links expire in minutes; Cold after 90 days through a lifecycle rule; deletion 12 months after programme completion by a monthly job, later. | E09-F05-US03E09-F05-US07E01-F11-NFR07 |
| Test database | Free-offer SQL database in the test environment, rebuilt with sample data and reset nightly. | E01-F06-US11E15-F02-US01E15-F02-US04 |
Every table has id (a GUID, generated on the phone for logged sets so a retry never duplicates), created_at and updated_at in UTC. Branch-scoped tables also carry franchise_id and branch_id, and franchise-scoped tables carry franchise_id; row-level security filters on them. Library tables are shared across the network.
People and access6 tables
- franchise_idthe franchise it belongs to → franchise
- codeshort code, e.g. ECR
- namebranch name
- entra_object_idthe person's Entra External ID account
- emailsign-in email
- full_namename
- phonephone
- statusinvited, active, deletion requested or deleted
- deletion_requested_atwhen deletion was requested
- person_idwho accepted → person
- documentterms or privacy
- versiondocument version
- accepted_atwhen
Movement library9 tables
- codefamily code, e.g. 43
- namefamily name
- base_typee.g. Calisthenics & Strength
- sub_typesub type
- muscle_groupsmuscles worked
- movement_idits family → movement
- codevariant code, e.g. 43.1A
- stage1 to 5, from the code
- levelL1 to L3, from the agreed stage mapping
- namevariant name
- definitiondefinition and technique
- training_methodhow to train it
- success_criteriawhat counts as passed
- safety_requirementsafety rule
- statusdraft or published
- variant_idthe variant changed → movement_variant
- versionrevision number
- changeschanged fields (JSON)
- statusdraft or published
- edited_byExecutive Coach who edited and published → person
- published_atwhen published
- variant_idthe variant it shows → movement_variant
- kindphoto or video
- blob_pathprivate Blob Storage path
- uploaded_bywho uploaded it → person
- codeinfrastructure code
- namename
- specificationspecification
- variant_idthe variant → movement_variant
- infrastructure_idthe equipment → infrastructure_code
- infrastructure_idthe equipment → infrastructure_code
- branch_ida branch that has it → branch
- namecategory name
- category_idthe category → slot_category
- variant_idan allowed variant → movement_variant
Programmes and gameplans5 tables
- nameprogramme name
- weekslength in weeks
- statusdraft or published
- versiontemplate version
- programme_idthe template → programme
- week1 to 12
- dayMon to Sun
- slote.g. Pull 1
- category_idthe slot's list → slot_category
- variant_idthe movement → movement_variant
- targetssets, reps, time (s), distance (ft), weight (kg), rest (s), RPE
- programme_idthe programme → programme
- namehabit
- sort_orderdisplay order
- enrolment_idthe player's enrolment → enrolment
- weekprogramme week
- statusdraft or published
- published_bycoach who published → person
- published_atwhen published
- gameplan_idthe week → gameplan
- dayMon to Sun
- slote.g. Pull 1
- variant_idthe movement → movement_variant
- targetssets, reps, time (s), distance (ft), weight (kg), rest (s), RPE
Batches and sessions5 tables
- branch_idwhere it trains → branch
- programme_idthe programme it runs → programme
- namebatch name
- daystraining days
- start_timestart time
- length_minsession length
- capacityplaces
- start_datefirst day
- person_idthe player → person
- batch_idthe batch → batch
- programme_idthe programme → programme
- start_datefrom when
- statusactive or ended
- session_idthe session → session
- person_idthe player → person
- statuspresent or absent
- marked_bythe coach → person
Training and progress5 tables
- gameplan_item_idwhat was prescribed → gameplan_item
- session_idthe session → session
- person_idthe player → person
- set_noset number
- donecompleted or not
- repsreps
- weight_kgload
- time_stime
- logged_atphone time of logging
- person_idthe player → person
- week_startweek
- weight_kgweight
- waist_cmwaist
- person_idthe player → person
- variant_idthe variant → movement_variant
- unlocked_bycoach who unlocked → person
- unlocked_atwhen unlocked
- ready_atwhen the player tapped Ready
- resultpassed, not yet or not assessed
- assessed_bycoach who assessed → person
- assessed_atwhen
- person_idthe player → person
- levelL1, L2 or L3
- awarded_atwhen
Nutrition6 tables
- player_idthe player → person
- nutritionist_idthe nutritionist → person
- notesgeneral guidance
- valid_fromfrom when
- statusactive or ended
- nutrition_plan_idthe plan → nutrition_plan
- mealbreakfast, lunch, dinner or snacks
- guidancefoods and portions
- player_idthe player → person
- daydate
- mealbreakfast, lunch, dinner or snack
- snack_no1, 2 and so on for snacks
- tickedas per plan; unticked by default
- ticked_atwhen ticked
- meal_entry_idthe meal it belongs to → meal_entry
- blob_pathprivate Blob Storage path
- taken_atphone time
- uploaded_atupload time
- player_idthe player → person
- daydate
- reviewon plan, partly or off plan
- reviewed_bynutritionist or coach → person
- reviewed_atwhen
Safety, audit and imports4 tables
- person_idthe player → person
- versionquestion set version
- answersencrypted answers
- restrictionsrestrictions shown to coaches
- submitted_atwhen
- player_idthe player → person
- author_idthe coach who wrote it → person
- session_idthe session → session
- tagse.g. knee pain, fatigue
- notetext
- actor_idwho acted → person
- table_nametable changed
- record_idrecord changed
- actioncreate, update, delete, or view for staff views of nutrition data and meal photos
- changesbefore and after (JSON)
- atwhen
- kindmovement workbook or player list
- file_nameuploaded file
- statuschecked, imported or failed
- rows_totalrows in the file
- rows_rejectedrows rejected
- rejectionsrow and reason for each rejection (JSON)
- run_bywho ran it → person
- run_atwhen