schema.sql 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263
  1. -- PackIt Database Schema
  2. -- Run this once to set up all required tables.
  3. CREATE DATABASE IF NOT EXISTS packit CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
  4. USE packit;
  5. -- Activity groups (categories)
  6. CREATE TABLE IF NOT EXISTS activity_groups (
  7. groupID INT AUTO_INCREMENT PRIMARY KEY,
  8. groupName VARCHAR(100) NOT NULL,
  9. sortOrder INT DEFAULT 0
  10. );
  11. -- Activities
  12. CREATE TABLE IF NOT EXISTS activities (
  13. activityID INT AUTO_INCREMENT PRIMARY KEY,
  14. groupID INT NOT NULL,
  15. activityName VARCHAR(150) NOT NULL,
  16. sortOrder INT DEFAULT 0,
  17. FOREIGN KEY (groupID) REFERENCES activity_groups(groupID) ON DELETE CASCADE
  18. );
  19. -- Item groups
  20. CREATE TABLE IF NOT EXISTS item_groups (
  21. groupID INT AUTO_INCREMENT PRIMARY KEY,
  22. groupName VARCHAR(100) NOT NULL,
  23. sortOrder INT DEFAULT 0
  24. );
  25. -- Items
  26. CREATE TABLE IF NOT EXISTS items (
  27. itemID INT AUTO_INCREMENT PRIMARY KEY,
  28. groupID INT NOT NULL,
  29. itemName VARCHAR(150) NOT NULL,
  30. sortOrder INT DEFAULT 0,
  31. FOREIGN KEY (groupID) REFERENCES item_groups(groupID) ON DELETE CASCADE
  32. );
  33. -- Relation between activities and items
  34. CREATE TABLE IF NOT EXISTS activity_item_map (
  35. activityID INT NOT NULL,
  36. itemID INT NOT NULL,
  37. quantity INT NOT NULL DEFAULT 1,
  38. PRIMARY KEY (activityID, itemID),
  39. FOREIGN KEY (activityID) REFERENCES activities(activityID) ON DELETE CASCADE,
  40. FOREIGN KEY (itemID) REFERENCES items(itemID) ON DELETE CASCADE
  41. );
  42. -- Stored selection hashes (for shareable URLs)
  43. -- hash is a 5-character SHA-256 prefix, grown one character at a time by
  44. -- list.php when a shorter prefix is already taken by a different selection.
  45. CREATE TABLE IF NOT EXISTS selection_hashes (
  46. hashID INT AUTO_INCREMENT PRIMARY KEY,
  47. hash VARCHAR(16) NOT NULL UNIQUE,
  48. activity_ids VARCHAR(500) NOT NULL,
  49. created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
  50. INDEX idx_activity_ids (activity_ids)
  51. );
  52. -- Admin users
  53. CREATE TABLE IF NOT EXISTS admin_users (
  54. adminID INT AUTO_INCREMENT PRIMARY KEY,
  55. username VARCHAR(50) NOT NULL UNIQUE,
  56. password_hash VARCHAR(255) NOT NULL
  57. );
  58. -- Failed admin logins, used by admin/login.php to throttle brute-force
  59. -- attempts. Rows older than a day are pruned opportunistically on each write.
  60. CREATE TABLE IF NOT EXISTS login_attempts (
  61. attemptID INT AUTO_INCREMENT PRIMARY KEY,
  62. ip VARCHAR(45) NOT NULL,
  63. username VARCHAR(50) NOT NULL,
  64. attempted_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
  65. INDEX idx_ip_time (ip, attempted_at),
  66. INDEX idx_user_time (username, attempted_at)
  67. );
  68. -- -----------------------------------------------
  69. -- Sample data
  70. -- -----------------------------------------------
  71. INSERT INTO activity_groups (groupName, sortOrder) VALUES
  72. ('Overnight', 1), -- groupID 1
  73. ('Rescue & Safety', 2), -- groupID 2
  74. ('Water Activities', 3), -- groupID 3
  75. ('Winter Sports', 4); -- groupID 4
  76. -- activityID 1=Camping 2=Hiking 3=Bivouac 4=First Aid 5=Mountain Rescue
  77. -- activityID 6=Kayaking 7=Swimming 8=Skiing 9=Snowshoeing
  78. INSERT INTO activities (groupID, activityName, sortOrder) VALUES
  79. (1, 'Camping', 1),
  80. (1, 'Hiking', 2),
  81. (1, 'Bivouac', 3),
  82. (2, 'First Aid', 1),
  83. (2, 'Mountain Rescue', 2),
  84. (3, 'Kayaking', 1),
  85. (3, 'Swimming', 2),
  86. (4, 'Skiing', 1),
  87. (4, 'Snowshoeing', 2);
  88. INSERT INTO item_groups (groupName, sortOrder) VALUES
  89. ('Clothing', 1), -- groupID 1
  90. ('Shelter', 2), -- groupID 2
  91. ('Navigation', 3), -- groupID 3
  92. ('Medical', 4), -- groupID 4
  93. ('Water & Food', 5), -- groupID 5
  94. ('Safety Gear', 6); -- groupID 6
  95. -- Items with their resulting auto_increment IDs:
  96. -- 1 Base layer top (Clothing)
  97. -- 2 Base layer bottom (Clothing)
  98. -- 3 Fleece jacket (Clothing)
  99. -- 4 Rain jacket (Clothing)
  100. -- 5 Gloves (Clothing)
  101. -- 6 Warm hat (Clothing)
  102. -- 7 Hiking boots (Clothing)
  103. -- 8 Wetsuit (Clothing)
  104. -- 9 Ski jacket (Clothing)
  105. -- 10 Ski pants (Clothing)
  106. -- 11 Ski boots (Clothing)
  107. -- 12 Tent (Shelter)
  108. -- 13 Sleeping bag (Shelter)
  109. -- 14 Sleeping mat (Shelter)
  110. -- 15 Bivouac bag (Shelter)
  111. -- 16 Topographic map (Navigation)
  112. -- 17 Compass (Navigation)
  113. -- 18 GPS device (Navigation)
  114. -- 19 First aid kit (Medical)
  115. -- 20 Emergency blanket (Medical)
  116. -- 21 Tourniquet (Medical)
  117. -- 22 SAM splint (Medical)
  118. -- 23 Water bottle (Water & Food)
  119. -- 24 Water filter (Water & Food)
  120. -- 25 Trail snacks (Water & Food)
  121. -- 26 Stove & fuel (Water & Food)
  122. -- 27 Cooking pot (Water & Food)
  123. -- 28 Headlamp + batteries (Safety Gear)
  124. -- 29 Whistle (Safety Gear)
  125. -- 30 Rope (30m) (Safety Gear)
  126. -- 31 Avalanche probe (Safety Gear)
  127. -- 32 Avalanche transceiver (Safety Gear)
  128. -- 33 Shovel (Safety Gear)
  129. -- 34 Life jacket (Safety Gear)
  130. -- 35 Paddle float (Safety Gear)
  131. INSERT INTO items (groupID, itemName, sortOrder) VALUES
  132. (1, 'Base layer top', 1),
  133. (1, 'Base layer bottom', 2),
  134. (1, 'Fleece jacket', 3),
  135. (1, 'Rain jacket', 4),
  136. (1, 'Gloves', 5),
  137. (1, 'Warm hat', 6),
  138. (1, 'Hiking boots', 7),
  139. (1, 'Wetsuit', 8),
  140. (1, 'Ski jacket', 9),
  141. (1, 'Ski pants', 10),
  142. (1, 'Ski boots', 11),
  143. (2, 'Tent', 1),
  144. (2, 'Sleeping bag', 2),
  145. (2, 'Sleeping mat', 3),
  146. (2, 'Bivouac bag', 4),
  147. (3, 'Topographic map', 1),
  148. (3, 'Compass', 2),
  149. (3, 'GPS device', 3),
  150. (4, 'First aid kit', 1),
  151. (4, 'Emergency blanket', 2),
  152. (4, 'Tourniquet', 3),
  153. (4, 'SAM splint', 4),
  154. (5, 'Water bottle', 1),
  155. (5, 'Water filter', 2),
  156. (5, 'Trail snacks', 3),
  157. (5, 'Stove & fuel', 4),
  158. (5, 'Cooking pot', 5),
  159. (6, 'Headlamp + spare batteries', 1),
  160. (6, 'Whistle', 2),
  161. (6, 'Rope (30m)', 3),
  162. (6, 'Avalanche probe', 4),
  163. (6, 'Avalanche transceiver', 5),
  164. (6, 'Shovel', 6),
  165. (6, 'Life jacket', 7),
  166. (6, 'Paddle float', 8);
  167. -- -----------------------------------------------
  168. -- Activity -> Item mappings (all IDs verified)
  169. -- -----------------------------------------------
  170. -- activityID 1: Camping
  171. INSERT INTO activity_item_map (activityID, itemID) VALUES
  172. (1, 1),(1, 2),(1, 3),(1, 4),(1, 7),
  173. (1,12),(1,13),(1,14),
  174. (1,16),(1,17),
  175. (1,19),(1,20),
  176. (1,23),(1,24),(1,25),(1,26),(1,27),
  177. (1,28),(1,29);
  178. -- activityID 2: Hiking
  179. INSERT INTO activity_item_map (activityID, itemID) VALUES
  180. (2, 1),(2, 2),(2, 3),(2, 4),(2, 7),
  181. (2,16),(2,17),(2,18),
  182. (2,19),(2,20),
  183. (2,23),(2,24),(2,25),
  184. (2,28),(2,29);
  185. -- activityID 3: Bivouac
  186. INSERT INTO activity_item_map (activityID, itemID) VALUES
  187. (3, 1),(3, 2),(3, 3),(3, 4),(3, 5),(3, 6),(3, 7),
  188. (3,14),(3,15),
  189. (3,16),(3,17),
  190. (3,19),(3,20),
  191. (3,23),(3,25),
  192. (3,28),(3,29);
  193. -- activityID 4: First Aid
  194. INSERT INTO activity_item_map (activityID, itemID) VALUES
  195. (4,19),(4,20),(4,21),(4,22),
  196. (4,28),(4,29);
  197. -- activityID 5: Mountain Rescue
  198. INSERT INTO activity_item_map (activityID, itemID) VALUES
  199. (5, 1),(5, 3),(5, 4),(5, 5),(5, 6),
  200. (5,16),(5,17),(5,18),
  201. (5,19),(5,20),(5,21),(5,22),
  202. (5,28),(5,29),(5,30);
  203. -- activityID 6: Kayaking
  204. INSERT INTO activity_item_map (activityID, itemID) VALUES
  205. (6, 1),(6, 4),(6, 8),
  206. (6,19),(6,20),
  207. (6,23),(6,24),
  208. (6,28),(6,29),
  209. (6,34),(6,35);
  210. -- activityID 7: Swimming
  211. INSERT INTO activity_item_map (activityID, itemID) VALUES
  212. (7, 8),
  213. (7,19),(7,20),
  214. (7,34);
  215. -- activityID 8: Skiing
  216. INSERT INTO activity_item_map (activityID, itemID) VALUES
  217. (8, 1),(8, 2),(8, 5),(8, 6),(8, 9),(8,10),(8,11),
  218. (8,16),(8,17),(8,18),
  219. (8,19),(8,20),
  220. (8,23),(8,25),
  221. (8,28),(8,29),
  222. (8,31),(8,32),(8,33);
  223. -- activityID 9: Snowshoeing
  224. INSERT INTO activity_item_map (activityID, itemID) VALUES
  225. (9, 1),(9, 2),(9, 3),(9, 4),(9, 5),(9, 6),(9, 7),
  226. (9,16),(9,17),
  227. (9,19),(9,20),
  228. (9,23),(9,24),(9,25),
  229. (9,28),(9,29),
  230. (9,31);
  231. -- -----------------------------------------------
  232. -- Default admin user
  233. -- Username: admin Password: packit-admin
  234. -- Change the password after first login!
  235. -- -----------------------------------------------
  236. INSERT INTO admin_users (username, password_hash) VALUES
  237. ('admin', '$2y$12$eTfGi/R5IxHH5NQxrVe9.OijNfyFfpvT/X1i9aYgqZPRF6.Gu72hC');