Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
170 commits
Select commit Hold shift + click to select a range
37b86f3
chore: ignore the Code of Points PDF and extraction output
Oct 2, 2026
7dc6278
feat: add script to extract catalog data from the Code of Points
Oct 2, 2026
918aa79
feat: add catalog data extracted from the Code of Points
Oct 2, 2026
f3941c9
docs: document the Code of Points extraction and the data folder
Oct 2, 2026
a3e10b2
docs: add GraphQL schema draft for the catalog
Oct 10, 2026
84ecb5a
refactor: move GraphQL schema to backend/src
Oct 10, 2026
f791fbe
docs: add user data, login and error handling to the GraphQL schema
Oct 10, 2026
eb10d98
Merge origin/main into 11-graphql-schema-catalog
Oct 10, 2026
57947fa
docs: document the GraphQL API and AI usage for the schema
Oct 10, 2026
f736d05
docs: replace image with imageUrl in the GraphQL schema
Oct 10, 2026
88b17e4
docs: explain why GraphQL and not REST in the README
Oct 10, 2026
c4b28aa
docs: describe how the API scales and add limits to the schema
Oct 10, 2026
9de3ddf
docs: decide on user list pagination, propose tooling and add API tes…
Oct 10, 2026
76e423c
docs: use full text search with prefix matching for the catalog search
Oct 10, 2026
b1b5a9a
docs: add rules against SQL injection for the raw search query
Oct 10, 2026
bdc4c0f
docs: search without raw SQL using Prisma, a catalog entry table and …
Oct 10, 2026
4ffac1e
fix: correct split descriptions and names in the extraction script
Oct 12, 2026
3ed2f4e
docs: explain how the catalog data was extracted
Oct 12, 2026
4c3e287
fix: regenerate catalog data with corrected descriptions
Oct 12, 2026
7899290
docs: update README and data model after the extraction
Oct 12, 2026
930460f
Merge pull request #34 from IT2810-H26/16-extract-catalog-data-from-t…
xeniag Oct 13, 2026
1a82486
Merge remote-tracking branch 'origin/main' into dev
Oct 14, 2026
eeab6c4
Merge pull request #29 from IT2810-H26/11-graphql-schema-catalog
anettkva Oct 14, 2026
5bb2b07
chore: lint the backend with Node rules
Oct 14, 2026
7dca85c
build: add backend workspace with Prisma
Oct 14, 2026
4b684e4
docs: document AI usage for the database setup
Oct 14, 2026
02a4c9d
docs: add local database setup to README
Oct 14, 2026
15020b1
docs: explain the expected migrate status output on a fresh setup
Oct 14, 2026
5987cef
Merge pull request #36 from IT2810-H26/21-set-up-the-backend-and-prisma
anettkva Oct 15, 2026
c8c80eb
build: add the Prisma PostgreSQL adapter
Oct 15, 2026
0f0d79a
feat: add the database schema and first migration
Oct 15, 2026
bec4b45
docs: describe how the data model is stored in PostgreSQL
Oct 15, 2026
b67fb23
docs: update the search design after the schema work
Oct 15, 2026
c770b22
feat: add gymnast item list, routine timestamps and removed flag to t…
Oct 15, 2026
169fd80
fix: add sort indexes and a default for Routine.updatedAt
Oct 15, 2026
3947ed9
feat: filter the catalog by difficulty values
Oct 15, 2026
bcd1707
docs: document the review fixes and the difficulty decisions
Oct 15, 2026
f41dc4c
docs: document search safety, totalCount, Decimal sums and query plans
Oct 15, 2026
3b61315
feat: error on duplicate and missing list items, limit of 100, remove…
Oct 15, 2026
bd01f3b
docs: limit gymnast and routine names to 70 characters
Oct 15, 2026
b4f0ecd
feat: add the gymnast's element list and removed items to the API
Oct 15, 2026
5fd262b
docs: answer review questions on removed items, duplicates and limits
Oct 15, 2026
36b6a09
fix: check value ranges and routine positions in the database
Oct 15, 2026
d54415f
docs: update the example data to the new storage shape
Oct 15, 2026
f2bba06
docs: document AI usage for the database schema
Oct 15, 2026
0ee72c0
docs: clarify the data model after the fourth review
Oct 15, 2026
2373415
update docs
Oct 15, 2026
d007b13
Merge pull request #38 from IT2810-H26/22-create-the-database-schema
ronjalh Oct 15, 2026
9c5c46d
feat: add word normalization and the abbreviation list for the search
Oct 15, 2026
3dd5e5f
feat: seed the catalog and the search tables from data/
Oct 15, 2026
a507fc7
docs: explain seeding and how to look at the data
Oct 15, 2026
a77eb29
Merge pull request #50 from IT2810-H26/23-seed-the-catalog
ronjalh Oct 15, 2026
bc79974
chore: forbid raw SQL in the backend with a lint rule
Oct 16, 2026
e4a760e
feat: add the catalog search with keyset pagination
Oct 16, 2026
a11fc45
docs: describe the catalog search in the README and API.md
Oct 16, 2026
5cc990c
docs: update the docs after the search and explain its decisions
Oct 16, 2026
c1de998
feat: set up Tailwind CSS, shadcn/ui and Lucide icons
Oct 16, 2026
51ca858
docs: document how Tailwind CSS works with our own CSS
Oct 16, 2026
bb34772
Merge origin/dev into 37-add-missing-fields-to-graphql-schema
Oct 16, 2026
f20ac15
feat: tighten the catalog search after review
Oct 16, 2026
b4e3f64
Merge main into dev: bring in the colours (PR #35)
Oct 16, 2026
61100aa
chore: forbid $queryRawTyped and mode: 'insensitive' in the backend
Oct 16, 2026
6dba3d6
docs: describe the review changes to the search and why
Oct 16, 2026
a061e0e
Merge pull request #53 from IT2810-H26/51-set-up-shadcn-ui-and-lucide
anettkva Oct 16, 2026
92d0c21
Merge pull request #56 from IT2810-H26/merge-main-into-dev
anettkva Oct 16, 2026
feece6e
docs: describe the search text limits in schema.graphql
Oct 16, 2026
21506ae
Merge origin/dev into 37-add-missing-fields-to-graphql-schema
Oct 16, 2026
8abeb1f
Merge origin/dev into 24-add-indexes-and-search
Oct 16, 2026
7afdfc7
Merge pull request #52 from IT2810-H26/24-add-indexes-and-search
ronjalh Oct 16, 2026
48a3b51
feat: expose design tokens as Tailwind utilities
Oct 16, 2026
41097f6
feat: add reusable element variant card
Oct 16, 2026
9cf882e
chore: resolve merge conflicts with dev
Oct 16, 2026
5e0fffe
backend: added resolver, index.ts and updated package.json for seamle…
Oct 16, 2026
fb142ce
feat: add catalog lookup for element details
Oct 16, 2026
3c1c370
fix: reuse difficulty badge in element variants
Oct 16, 2026
9f23af7
feat: build modular element detail page
Oct 16, 2026
419666f
fix: use existing light text token for actions
Oct 16, 2026
2f5dfb7
fix: added project base to vite.config.ts
Oct 16, 2026
d945cf4
feat: add the GraphQL server with the catalog queries
Oct 16, 2026
b33ad8c
Merge the VM setup branch (#66) into the server branch
Oct 16, 2026
5027777
Merge pull request #59 from IT2810-H26/schema-search-argument-docs
xeniag Oct 16, 2026
2278921
feat: add your gymnasts overview page
Oct 16, 2026
5091f20
fix: repair schema fields swallowed by doc comments in the dev merge
Oct 17, 2026
4e97e06
fix: dark mode tokens, D-value badge tokens and README
Oct 17, 2026
c08f291
fix: drop role=img from DifficultyBadge and format with Prettier
Oct 17, 2026
1d8a98e
fix: format with Prettier, copy images to dist and drop role=img from…
Oct 17, 2026
74b3c1a
feat: make gymnast list changes no-ops and Routine.dScore nullable
Oct 17, 2026
630b938
style: format schema.graphql with Prettier
Oct 17, 2026
fb757b7
feat: add a script for synthetic test data and measure the search
Oct 17, 2026
1189f25
feat: set up Apollo Client in the frontend
Oct 17, 2026
aea1ed0
feat: add calculateDScore for the calculator
Oct 17, 2026
bcd34bd
chore: generate TypeScript types from the GraphQL schema
Oct 17, 2026
a592ac3
feat: add access tokens and rotating refresh tokens
Oct 17, 2026
4e1fcb7
Merge #49 (schema fields) into the user-data resolvers branch
Oct 17, 2026
6392b73
feat: add the resolvers for gymnasts, their lists and routines
Oct 17, 2026
48bec77
fix: deleted index.ts and resolvers.ts to avoid redundant implementat…
Oct 17, 2026
01f3bfe
docs: add VM_SETUP.md documentation
Oct 17, 2026
a202528
docs: updated .env.example
Oct 17, 2026
d479af6
fix: updated package.json fallback link
Oct 17, 2026
b91a14b
fead: update app.tsx
Oct 17, 2026
afe4b48
docs: updated reade project link
Oct 17, 2026
85be226
docs: updated AI_USAGE.md
Oct 17, 2026
6005300
fix: removed tailwint import that was breaking the build
Oct 17, 2026
855cbce
fix: format files
Oct 17, 2026
cf7e89a
Merge pull request #61 from IT2810-H26/60-expose-design-tokens
xeniag Oct 18, 2026
c88ae1c
Merge branch 'dev' into 26-set-up-the-database-on-the-vm
xeniag Oct 19, 2026
3bf3d26
Merge pull request #49 from IT2810-H26/37-add-missing-fields-to-graph…
xeniag Oct 19, 2026
01011ff
Merge branch 'dev' into 26-set-up-the-database-on-the-vm
xeniag Oct 20, 2026
07e4c57
Merge pull request #66 from IT2810-H26/26-set-up-the-database-on-the-vm
xeniag Oct 20, 2026
39d08ac
Merge dev into 28-graphql-server-catalog
Oct 21, 2026
84116e6
fix: mask every unexpected error in formatError
Oct 21, 2026
a2e060f
fix: read the difficulty badge once for screen readers
Oct 21, 2026
dbf9f8c
fix: show the action status text and size the icons
Oct 21, 2026
d8c7459
fix: label the back button and skip an empty description
Oct 21, 2026
3a95713
fix: style the headings of the not-found and error states
Oct 21, 2026
d592f34
fix: shorten the diagram alt text and drop the figure element
Oct 21, 2026
564721a
fix: use one badge label and a utility class in the metadata card
Oct 21, 2026
d8a9cdd
fix: replace role=img on ElementValueBadge with a screen reader label
Oct 21, 2026
7c854e0
fix: use a utility class and one badge label in the variant cards
Oct 21, 2026
47a387c
fix: handle a missing image and a trailing slash in the base URL
Oct 21, 2026
64c6e80
fix: look up difficulty letters with a map that tolerates rounding
Oct 21, 2026
e5992f3
Merge pull request #65 from IT2810-H26/28-graphql-server-catalog
anettkva Oct 21, 2026
70f725f
fix: import the global styles in App and set the router basename
Oct 21, 2026
5ede98d
Merge dev into 48-element-variant-card
Oct 21, 2026
7c7ea54
Merge branch '63-element-detail-page' into 67-your-gymnasts-page
Oct 21, 2026
5bc2ad3
fix: add a heading to the gymnast list and move the live region first
Oct 21, 2026
946217a
fix: close the heading regex in the gymnast list test
Oct 21, 2026
9a837ab
Merge pull request #62 from IT2810-H26/48-element-variant-card
anettkva Oct 21, 2026
220570b
Merge branch '28-graphql-server-catalog' into 72-calculate-dscore
Oct 21, 2026
6e26650
Merge branch '72-calculate-dscore' into 74-graphql-codegen
Oct 21, 2026
f37d1a0
Merge branch '74-graphql-codegen' into 70-session-tokens
Oct 21, 2026
e76b882
Merge branch '70-session-tokens' into 73-user-data-resolvers
Oct 21, 2026
eec41cf
Merge remote-tracking branch 'origin/dev' into 63-element-detail-page
Oct 21, 2026
e87a7a1
Merge branch '63-element-detail-page' into 67-your-gymnasts-page
Oct 21, 2026
e266004
Merge pull request #64 from IT2810-H26/63-element-detail-page
anettkva Oct 21, 2026
c3581ab
Merge pull request #68 from IT2810-H26/67-your-gymnasts-page
anettkva Oct 21, 2026
e68f46e
Merge remote-tracking branch 'origin/dev' into 72-calculate-dscore
Oct 21, 2026
66a5314
Merge remote-tracking branch 'origin/dev' into 25-synthetic-test-data
Oct 21, 2026
7859fcc
Merge remote-tracking branch 'origin/dev' into 75-apollo-client
Oct 21, 2026
08d46af
Merge pull request #77 from IT2810-H26/72-calculate-dscore
anettkva Oct 21, 2026
21e1b17
Merge remote-tracking branch 'origin/72-calculate-dscore' into 74-gra…
Oct 21, 2026
825dbe3
Merge remote-tracking branch 'origin/dev' into 74-graphql-codegen
Oct 21, 2026
5c20e3a
Merge remote-tracking branch 'origin/74-graphql-codegen' into 70-sess…
Oct 21, 2026
7be6e59
Merge remote-tracking branch 'origin/70-session-tokens' into 73-user-…
Oct 21, 2026
630d1ad
chore: generate the Prisma client and GraphQL types before typecheck …
Oct 21, 2026
8498eca
Merge pull request #78 from IT2810-H26/74-graphql-codegen
anettkva Oct 21, 2026
f732c3f
Merge remote-tracking branch 'origin/dev' into 70-session-tokens
Oct 21, 2026
44da4b3
Merge remote-tracking branch 'origin/70-session-tokens' into 73-user-…
Oct 21, 2026
4bb6d2c
fix: sign the token with the real time in the Authorization header test
Oct 21, 2026
9fc29c7
style: format server.test.ts with Prettier
Oct 21, 2026
f2cea00
feat: warn at start when SESSION_SECRET is not set
Oct 21, 2026
2c9108f
docs: say where expired refresh tokens are deleted
Oct 21, 2026
332f8ca
docs: explain that an access token lives on after logout
Oct 21, 2026
d552fde
docs: record why the test files run one at a time
Oct 21, 2026
473b7d4
docs: remove two claims that were not verified
Oct 21, 2026
d74a497
feat: stop the server in production when SESSION_SECRET is missing
Oct 21, 2026
54eda8b
docs: set NODE_ENV=production and a real SESSION_SECRET on the VM
Oct 21, 2026
939adbf
Merge pull request #82 from IT2810-H26/70-session-tokens
anettkva Oct 21, 2026
1c408ab
Merge remote-tracking branch 'origin/dev' into 75-apollo-client
Oct 21, 2026
f245ced
Merge remote-tracking branch 'origin/dev' into 25-synthetic-test-data
Oct 21, 2026
7a62c8a
Merge remote-tracking branch 'origin/dev' into 73-user-data-resolvers
Oct 21, 2026
e509df8
Merge pull request #69 from IT2810-H26/25-synthetic-test-data
xeniag Oct 21, 2026
86c88db
Merge pull request #79 from IT2810-H26/73-user-data-resolvers
anettkva Oct 21, 2026
f375d81
Merge remote-tracking branch 'origin/dev' into 75-apollo-client
Oct 21, 2026
7f4bc52
fix: refresh the session before a request when the access token has e…
Oct 21, 2026
ed84434
fix: time out the login, refresh and logout requests after 5 seconds
Oct 21, 2026
869a714
docs: explain the refresh before requests and the request timeout
Oct 21, 2026
5ee72e6
docs: describe the Apache proxy for the API on the VM
Oct 21, 2026
21ad013
docs: document the VM API address and the bundle size decision
Oct 21, 2026
783b054
Merge pull request #80 from IT2810-H26/75-apollo-client
anettkva Oct 21, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
9 changes: 9 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ dist
dist-ssr
*.local

# The Prisma client (`npm run db:generate`) and the GraphQL types (`npm run codegen`)
backend/src/generated

# Environment variables
.env
.env.*
Expand All @@ -26,3 +29,9 @@ dist-ssr
*.njsproj
*.sln
*.sw?

# Code of Points extraction: the PDF must never be committed
scripts/extract-cop/en_1.1.-WAG-Code-of-Points-2025-2028.pdf
scripts/extract-cop/review.html
scripts/extract-cop/.venv
__pycache__
416 changes: 401 additions & 15 deletions README.md

Large diffs are not rendered by default.

22 changes: 22 additions & 0 deletions backend/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Copy this file to .env and fill in your own values. .env is not committed.
#
# Runtime server connection (wag_app - restricted CRUD permissions)
DATABASE_URL="postgresql://wag_app:YOUR_APP_PASSWORD@localhost:5432/wag_catalog"

# Migration connection string (wag_migrator - schema owner for migrations & setup)
MIGRATION_DATABASE_URL="postgresql://wag_migrator:YOUR_MIGRATOR_PASSWORD@localhost:5432/wag_catalog"

# The GraphQL server (npm run dev -w backend). All three are optional.
# The port of the server. The backend should be on 3001 on the virtual machine.
# PORT=3001
# The address the drawings are served from, without a final slash. In development
# the server serves them itself. On the virtual machine it is the Apache address,
# for example http://it2810-XX.idi.ntnu.no/project2/images
# IMAGE_BASE_URL=http://localhost:3001/images
# The addresses that may call the API from a browser, separated by commas.
# CORS_ORIGIN=http://localhost:5173

# Signs the access tokens (optional). At least 32 random characters. Without it there
# are no tokens and `me` is always null.
# Make one with: node -e "console.log(require('node:crypto').randomBytes(48).toString('base64url'))"
# SESSION_SECRET=
39 changes: 39 additions & 0 deletions backend/codegen.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// GraphQL Code Generator: makes TypeScript types from src/schema.graphql, so a
// resolver that does not match the schema fails `tsc`. Run it with
// `npm run codegen`. The result (src/generated/graphql.ts) is not committed,
// like the Prisma client in the same folder.
import type { CodegenConfig } from '@graphql-codegen/cli'

const config: CodegenConfig = {
schema: 'src/schema.graphql',
generates: {
'src/generated/graphql.ts': {
plugins: ['typescript', 'typescript-resolvers'],
config: {
// What every resolver gets as its third argument.
contextType: '../server/context.js#Context',
useTypeImports: true,
enumsAsTypes: true,
// GraphQL types that resolvers receive as database rows. The fields of
// the row do not have to match the schema: a field resolver converts
// them (for example Decimal to number).
mappers: {
Apparatus: '../generated/prisma/client.js#Apparatus as ApparatusRow',
ElementGroup:
'../generated/prisma/client.js#ElementGroup as ElementGroupRow',
Coach: '../generated/prisma/client.js#Coach as CoachRow',
Gymnast: '../generated/prisma/client.js#Gymnast as GymnastRow',
Routine: '../generated/prisma/client.js#Routine as RoutineRow',
// An element or vault row with a __typename, see server/items.ts.
CatalogItem: '../server/items.js#Item',
CatalogConnection: '../server/items.js#ConnectionRow',
Element: '../server/items.js#ElementItem',
Vault: '../server/items.js#VaultItem',
},
scalars: { DateTime: 'Date' },
},
},
},
}

export default config
49 changes: 49 additions & 0 deletions backend/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
{
"name": "backend",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "tsx watch src/index.ts",
"start": "tsx src/index.ts",
"prebuild": "npm run generate",
"build": "tsc",
"setup": "DATABASE_URL=${MIGRATION_DATABASE_URL:-$DATABASE_URL} prisma migrate deploy && DATABASE_URL=${MIGRATION_DATABASE_URL:-$DATABASE_URL} npm run prisma:seed",
"pretypecheck": "npm run generate",
"typecheck": "tsc --noEmit",
"generate": "npm run prisma:generate && npm run codegen",
"prisma:generate": "prisma generate",
"codegen": "graphql-codegen --config codegen.ts",
"prisma:migrate": "prisma migrate dev",
"prisma:deploy": "prisma migrate deploy",
"prisma:seed": "prisma db seed",
"synthetic": "tsx src/seed/synthetic.ts",
"prisma:studio": "prisma studio"
},
"engines": {
"node": ">=24"
},
"devDependencies": {
"@graphql-codegen/cli": "^7.4.6",
"@graphql-codegen/typescript": "^6.1.2",
"@graphql-codegen/typescript-resolvers": "^6.1.1",
"@types/cors": "^2.8.19",
"@types/express": "^5.0.6",
"@types/node": "^24.19.2",
"prisma": "^7.10.1",
"typescript": "~6.0.2"
},
"dependencies": {
"@apollo/server": "^5.5.1",
"@as-integrations/express5": "^1.1.2",
"@prisma/adapter-pg": "^7.10.1",
"@prisma/client": "^7.10.1",
"cors": "^2.8.6",
"dataloader": "^2.2.3",
"dotenv": "^18.0.8",
"express": "^5.3.0",
"graphql": "^16.14.2",
"jose": "^6.2.12",
"tsx": "^4.23.15"
}
}
16 changes: 16 additions & 0 deletions backend/prisma.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// Prisma configuration. Prisma 7 reads the database URL from here, not from
// schema.prisma. DATABASE_URL is loaded from backend/.env.
import 'dotenv/config'
import { defineConfig } from 'prisma/config'

export default defineConfig({
schema: 'prisma/schema.prisma',
migrations: {
path: 'prisma/migrations',
// `prisma db seed` (npm run db:seed) runs the seed script.
seed: 'tsx src/seed/seed.ts',
},
datasource: {
url: process.env['DATABASE_URL'],
},
})
Loading