Skip to main content

max / goingson

Update path deps and resource paths for ~/Code directory layout Move project docs into repo. Update Cargo.toml path dependencies and tauri.conf.json theme resource glob for new Shared/ location. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Author: Max J. <87768334+MaxJMath@users.noreply.github.com> · 2026-03-30 02:15 UTC
Commit: 4e918b4121eca86ba2570ed4aea20cab4d36f87e
Parent: 58aa9cc
10 files changed, +2023 insertions, -95 deletions
M Cargo.lock +134 -90
@@ -71,7 +71,7 @@ dependencies = [
71 71 "cssparser 0.35.0",
72 72 "html5ever 0.35.0",
73 73 "maplit",
74 - "tendril",
74 + "tendril 0.4.3",
75 75 "url",
76 76 ]
77 77
@@ -86,18 +86,9 @@ dependencies = [
86 86
87 87 [[package]]
88 88 name = "anyhow"
89 - version = "1.0.101"
89 + version = "1.0.102"
90 90 source = "registry+https://github.com/rust-lang/crates.io-index"
91 - checksum = "5f0e0fee31ef5ed1ba1316088939cea399010ed7731dba877ed44aeb407a75ea"
92 -
93 - [[package]]
94 - name = "ar_archive_writer"
95 - version = "0.5.1"
96 - source = "registry+https://github.com/rust-lang/crates.io-index"
97 - checksum = "7eb93bbb63b9c227414f6eb3a0adfddca591a8ce1e9b60661bb08969b87e340b"
98 - dependencies = [
99 - "object",
100 - ]
91 + checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c"
101 92
102 93 [[package]]
103 94 name = "arbitrary"
@@ -157,9 +148,9 @@ dependencies = [
157 148
158 149 [[package]]
159 150 name = "async-compression"
160 - version = "0.4.37"
151 + version = "0.4.41"
161 152 source = "registry+https://github.com/rust-lang/crates.io-index"
162 - checksum = "d10e4f991a553474232bc0a31799f6d24b034a84c0971d80d2e2f78b2e576e40"
153 + checksum = "d0f9ee0f6e02ffd7ad5816e9464499fba7b3effd01123b515c41d1697c43dad1"
163 154 dependencies = [
164 155 "compression-codecs",
165 156 "compression-core",
@@ -169,9 +160,9 @@ dependencies = [
169 160
170 161 [[package]]
171 162 name = "async-executor"
172 - version = "1.13.3"
163 + version = "1.14.0"
173 164 source = "registry+https://github.com/rust-lang/crates.io-index"
174 - checksum = "497c00e0fd83a72a79a39fcbd8e3e2f055d6f6c7e025f3b3d91f4f8e76527fb8"
165 + checksum = "c96bf972d85afc50bf5ab8fe2d54d1586b4e0b46c97c50a0c9e71e2f7bcd812a"
175 166 dependencies = [
176 167 "async-task",
177 168 "concurrent-queue",
@@ -259,7 +250,7 @@ checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11"
259 250 dependencies = [
260 251 "proc-macro2",
261 252 "quote",
262 - "syn 2.0.114",
253 + "syn 2.0.117",
263 254 ]
264 255
265 256 [[package]]
@@ -316,7 +307,7 @@ checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb"
316 307 dependencies = [
317 308 "proc-macro2",
318 309 "quote",
319 - "syn 2.0.114",
310 + "syn 2.0.117",
320 311 ]
321 312
322 313 [[package]]
@@ -382,6 +373,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
382 373 checksum = "2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06"
383 374
384 375 [[package]]
376 + name = "bit-set"
377 + version = "0.8.0"
378 + source = "registry+https://github.com/rust-lang/crates.io-index"
379 + checksum = "08807e080ed7f9d5433fa9b275196cfc35414f66a0c79d864dc51a0d825231a3"
380 + dependencies = [
381 + "bit-vec",
382 + ]
383 +
384 + [[package]]
385 + name = "bit-vec"
386 + version = "0.8.0"
387 + source = "registry+https://github.com/rust-lang/crates.io-index"
388 + checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7"
389 +
390 + [[package]]
385 391 name = "bitflags"
386 392 version = "1.3.2"
387 393 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -389,9 +395,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
389 395
390 396 [[package]]
391 397 name = "bitflags"
392 - version = "2.10.0"
398 + version = "2.11.0"
393 399 source = "registry+https://github.com/rust-lang/crates.io-index"
394 - checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3"
400 + checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af"
395 401 dependencies = [
396 402 "serde_core",
397 403 ]
@@ -459,9 +465,9 @@ dependencies = [
459 465
460 466 [[package]]
461 467 name = "bumpalo"
462 - version = "3.19.1"
468 + version = "3.20.2"
463 469 source = "registry+https://github.com/rust-lang/crates.io-index"
464 - checksum = "5dd9dc738b7a8311c7ade152424974d8115f2cdad61e8dab8dac9f2362298510"
470 + checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb"
465 471
466 472 [[package]]
467 473 name = "bytemuck"
@@ -496,7 +502,7 @@ version = "0.18.5"
496 502 source = "registry+https://github.com/rust-lang/crates.io-index"
497 503 checksum = "8ca26ef0159422fb77631dc9d17b102f253b876fe1586b03b803e63a309b4ee2"
498 504 dependencies = [
499 - "bitflags 2.10.0",
505 + "bitflags 2.11.0",
500 506 "cairo-sys-rs",
501 507 "glib",
502 508 "libc",
@@ -554,14 +560,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
554 560 checksum = "374b7c592d9c00c1f4972ea58390ac6b18cbb6ab79011f3bdc90a0b82ca06b77"
555 561 dependencies = [
556 562 "serde",
557 - "toml 0.9.11+spec-1.1.0",
563 + "toml 0.9.12+spec-1.1.0",
558 564 ]
559 565
560 566 [[package]]
561 567 name = "cc"
562 - version = "1.2.55"
568 + version = "1.2.58"
563 569 source = "registry+https://github.com/rust-lang/crates.io-index"
564 - checksum = "47b26a0954ae34af09b50f0de26458fa95369a0d478d8236d3f93082b219bd29"
570 + checksum = "e1e928d4b69e3077709075a938a05ffbedfa53a84c8f766efbf8220bb1ff60e1"
565 571 dependencies = [
566 572 "find-msvc-tools",
567 573 "shlex",
@@ -636,9 +642,9 @@ dependencies = [
636 642
637 643 [[package]]
638 644 name = "chrono"
639 - version = "0.4.43"
645 + version = "0.4.44"
640 646 source = "registry+https://github.com/rust-lang/crates.io-index"
641 - checksum = "fac4744fb15ae8337dc853fee7fb3f4e48c0fbaa23d0afe49c447b4fab126118"
647 + checksum = "c673075a2e0e5f4a1dde27ce9dee1ea4558c7ffe648f576438a20ca1d2acc4b0"
642 648 dependencies = [
643 649 "iana-time-zone",
644 650 "js-sys",
@@ -649,16 +655,6 @@ dependencies = [
649 655 ]
650 656
651 657 [[package]]
652 - name = "chumsky"
653 - version = "0.9.3"
654 - source = "registry+https://github.com/rust-lang/crates.io-index"
655 - checksum = "8eebd66744a15ded14960ab4ccdbfb51ad3b81f51f3f04a80adac98c985396c9"
656 - dependencies = [
657 - "hashbrown 0.14.5",
658 - "stacker",
659 - ]
660 -
661 - [[package]]
662 658 name = "cipher"
663 659 version = "0.4.4"
664 660 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -681,9 +677,9 @@ dependencies = [
681 677
682 678 [[package]]
683 679 name = "compression-codecs"
684 - version = "0.4.36"
680 + version = "0.4.37"
685 681 source = "registry+https://github.com/rust-lang/crates.io-index"
686 - checksum = "00828ba6fd27b45a448e57dbfe84f1029d4c9f26b368157e9a448a5f49a2ec2a"
682 + checksum = "eb7b51a7d9c967fc26773061ba86150f19c50c0d65c887cb1fbe295fd16619b7"
687 683 dependencies = [
688 684 "compression-core",
689 685 "flate2",
@@ -774,11 +770,11 @@ checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
774 770
775 771 [[package]]
776 772 name = "core-graphics"
777 - version = "0.24.0"
773 + version = "0.25.0"
778 774 source = "registry+https://github.com/rust-lang/crates.io-index"
779 - checksum = "fa95a34622365fa5bbf40b20b75dba8dfa8c94c734aea8ac9a5ca38af14316f1"
775 + checksum = "064badf302c3194842cf2c5d61f56cc88e54a759313879cdf03abdd27d0c3b97"
780 776 dependencies = [
781 - "bitflags 2.10.0",
777 + "bitflags 2.11.0",
782 778 "core-foundation 0.10.1",
783 779 "core-graphics-types",
784 780 "foreign-types 0.5.0",
@@ -791,7 +787,7 @@ version = "0.2.0"
791 787 source = "registry+https://github.com/rust-lang/crates.io-index"
792 788 checksum = "3d44a101f213f6c4cdc1853d4b78aef6db6bdfa3468798cc1d9912f4735013eb"
793 789 dependencies = [
794 - "bitflags 2.10.0",
790 + "bitflags 2.11.0",
795 791 "core-foundation 0.10.1",
796 792 "libc",
797 793 ]
@@ -901,13 +897,26 @@ dependencies = [
901 897 ]
902 898
903 899 [[package]]
900 + name = "cssparser"
901 + version = "0.36.0"
902 + source = "registry+https://github.com/rust-lang/crates.io-index"
903 + checksum = "dae61cf9c0abb83bd659dab65b7e4e38d8236824c85f0f804f173567bda257d2"
904 + dependencies = [
905 + "cssparser-macros",
906 + "dtoa-short",
907 + "itoa",
908 + "phf 0.13.1",
909 + "smallvec",
910 + ]
911 +
912 + [[package]]
904 913 name = "cssparser-macros"
905 914 version = "0.6.1"
906 915 source = "registry+https://github.com/rust-lang/crates.io-index"
907 916 checksum = "13b588ba4ac1a99f7f2964d24b3d896ddc6bf847ee3855dbd4366f058cfcd331"
908 917 dependencies = [
909 918 "quote",
910 - "syn 2.0.114",
919 + "syn 2.0.117",
911 920 ]
912 921
913 922 [[package]]
@@ -938,14 +947,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
938 947 checksum = "32a2785755761f3ddc1492979ce1e48d2c00d09311c39e4466429188f3dd6501"
939 948 dependencies = [
940 949 "quote",
941 - "syn 2.0.114",
950 + "syn 2.0.117",
942 951 ]
943 952
944 953 [[package]]
945 954 name = "darling"
946 - version = "0.21.3"
955 + version = "0.23.0"
947 956 source = "registry+https://github.com/rust-lang/crates.io-index"
948 - checksum = "9cdf337090841a411e2a7f3deb9187445851f91b309c0c0a29e05f74a00a48c0"
957 + checksum = "25ae13da2f202d56bd7f91c25fba009e7717a1e4a1cc98a76d844b65ae912e9d"
949 958 dependencies = [
950 959 "darling_core",
951 960 "darling_macro",
@@ -953,27 +962,26 @@ dependencies = [
953 962
954 963 [[package]]
955 964 name = "darling_core"
956 - version = "0.21.3"
965 + version = "0.23.0"
957 966 source = "registry+https://github.com/rust-lang/crates.io-index"
958 - checksum = "1247195ecd7e3c85f83c8d2a366e4210d588e802133e1e355180a9870b517ea4"
967 + checksum = "9865a50f7c335f53564bb694ef660825eb8610e0a53d3e11bf1b0d3df31e03b0"
959 968 dependencies = [
960 - "fnv",
961 969 "ident_case",
962 970 "proc-macro2",
963 971 "quote",
964 972 "strsim",
965 - "syn 2.0.114",
973 + "syn 2.0.117",
966 974 ]
967 975
968 976 [[package]]
969 977 name = "darling_macro"
970 - version = "0.21.3"
978 + version = "0.23.0"
971 979 source = "registry+https://github.com/rust-lang/crates.io-index"
972 - checksum = "d38308df82d1080de0afee5d069fa14b0326a88c14f15c5ccda35b4a6c414c81"
980 + checksum = "ac3984ec7bd6cfa798e62b4a642426a5be0e68f9401cfc2a01e3fa9ea2fcdb8d"
973 981 dependencies = [
974 982 "darling_core",
975 983 "quote",
976 - "syn 2.0.114",
984 + "syn 2.0.117",
977 985 ]
978 986
979 987 [[package]]
@@ -995,9 +1003,9 @@ dependencies = [
995 1003
996 1004 [[package]]
997 1005 name = "deranged"
998 - version = "0.5.5"
1006 + version = "0.5.8"
999 1007 source = "registry+https://github.com/rust-lang/crates.io-index"
1000 - checksum = "ececcb659e7ba858fb4f10388c250a7252eb0a27373f1a72b8748afdd248e587"
1008 + checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c"
1001 1009 dependencies = [
1002 1010 "powerfmt",
1003 1011 "serde_core",
@@ -1011,7 +1019,7 @@ checksum = "1e567bd82dcff979e4b03460c307b3cdc9e96fde3d73bed1496d2bc75d9dd62a"
1011 1019 dependencies = [
1012 1020 "proc-macro2",
1013 1021 "quote",
1014 - "syn 2.0.114",
1022 + "syn 2.0.117",
1015 1023 ]
1016 1024
1017 1025 [[package]]
@@ -1024,7 +1032,28 @@ dependencies = [
1024 1032 "proc-macro2",
1025 1033 "quote",
1026 1034 "rustc_version",
1027 - "syn 2.0.114",
1035 + "syn 2.0.117",
1036 + ]
1037 +
1038 + [[package]]
1039 + name = "derive_more"
1040 + version = "2.1.1"
1041 + source = "registry+https://github.com/rust-lang/crates.io-index"
1042 + checksum = "d751e9e49156b02b44f9c1815bcb94b984cdcc4396ecc32521c739452808b134"
1043 + dependencies = [
1044 + "derive_more-impl",
1045 + ]
1046 +
1047 + [[package]]
1048 + name = "derive_more-impl"
1049 + version = "2.1.1"
1050 + source = "registry+https://github.com/rust-lang/crates.io-index"
1051 + checksum = "799a97264921d8623a957f6c3b9011f3b5492f557bbb7a5a19b7fa6d06ba8dcb"
1052 + dependencies = [
1053 + "proc-macro2",
1054 + "quote",
1055 + "rustc_version",
1056 + "syn 2.0.117",
1028 1057 ]
1029 1058
1030 1059 [[package]]
@@ -1061,18 +1090,12 @@ dependencies = [
1061 1090 ]
1062 1091
1063 1092 [[package]]
1064 - name = "dispatch"
1065 - version = "0.2.0"
1066 - source = "registry+https://github.com/rust-lang/crates.io-index"
1067 - checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b"
1068 -
1069 - [[package]]
1070 1093 name = "dispatch2"
1071 - version = "0.3.0"
1094 + version = "0.3.1"
1072 1095 source = "registry+https://github.com/rust-lang/crates.io-index"
1073 - checksum = "89a09f22a6c6069a18470eb92d2298acf25463f14256d24778e1230d789a2aec"
1096 + checksum = "1e0e367e4e7da84520dedcac1901e4da967309406d1e51017ae1abfb97adbd38"
1074 1097 dependencies = [
1075 - "bitflags 2.10.0",
1098 + "bitflags 2.11.0",
1076 1099 "block2",
1077 1100 "libc",
1078 1101 "objc2",
@@ -1086,7 +1109,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0"
1086 1109 dependencies = [
1087 1110 "proc-macro2",
1088 1111 "quote",
1089 - "syn 2.0.114",
1112 + "syn 2.0.117",
1090 1113 ]
1091 1114
1092 1115 [[package]]
@@ -1109,7 +1132,7 @@ checksum = "0fbbb781877580993a8707ec48672673ec7b81eeba04cfd2310bd28c08e47c8f"
1109 1132 dependencies = [
1110 1133 "proc-macro2",
1111 1134 "quote",
1112 - "syn 2.0.114",
1135 + "syn 2.0.117",
1113 1136 ]
1114 1137
1115 1138 [[package]]
@@ -1122,6 +1145,21 @@ dependencies = [
1122 1145 ]
1123 1146
1124 1147 [[package]]
1148 + name = "dom_query"
1149 + version = "0.27.0"
1150 + source = "registry+https://github.com/rust-lang/crates.io-index"
1151 + checksum = "521e380c0c8afb8d9a1e83a1822ee03556fc3e3e7dbc1fd30be14e37f9cb3f89"
1152 + dependencies = [
1153 + "bit-set",
1154 + "cssparser 0.36.0",
1155 + "foldhash 0.2.0",
1156 + "html5ever 0.38.0",
1157 + "precomputed-hash",
1158 + "selectors 0.36.1",
1159 + "tendril 0.5.0",
1160 + ]
1161 +
1162 + [[package]]
1125 1163 name = "dotenvy"
1126 1164 version = "0.15.7"
1127 1165 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1190,14 +1228,14 @@ checksum = "e079f19b08ca6239f47f8ba8509c11cf3ea30095831f7fed61441475edd8c449"
1190 1228
1191 1229 [[package]]
1192 1230 name = "embed-resource"
1193 - version = "3.0.6"
1231 + version = "3.0.8"
1194 1232 source = "registry+https://github.com/rust-lang/crates.io-index"
1195 - checksum = "55a075fc573c64510038d7ee9abc7990635863992f83ebc52c8b433b8411a02e"
1233 + checksum = "63a1d0de4f2249aa0ff5884d7080814f446bb241a559af6c170a41e878ed2d45"
1196 1234 dependencies = [
1197 1235 "cc",
1198 1236 "memchr",
1199 1237 "rustc_version",
1200 - "toml 0.9.11+spec-1.1.0",
1238 + "toml 0.9.12+spec-1.1.0",
1201 1239 "vswhom",
1202 1240 "winreg",
1203 1241 ]
@@ -1241,7 +1279,7 @@ checksum = "67c78a4d8fdf9953a5c9d458f9efe940fd97a0cab0941c075a813ac594733827"
1241 1279 dependencies = [
1242 1280 "proc-macro2",
1243 1281 "quote",
1244 - "syn 2.0.114",
1282 + "syn 2.0.117",
1245 1283 ]
1246 1284
1247 1285 [[package]]
@@ -1252,9 +1290,9 @@ checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
1252 1290
1253 1291 [[package]]
1254 1292 name = "erased-serde"
1255 - version = "0.4.9"
1293 + version = "0.4.10"
1256 1294 source = "registry+https://github.com/rust-lang/crates.io-index"
1257 - checksum = "89e8918065695684b2b0702da20382d5ae6065cf3327bc2d6436bd49a71ce9f3"
1295 + checksum = "d2add8a07dd6a8d93ff627029c51de145e12686fbc36ecb298ac22e74cf02dec"
1258 1296 dependencies = [
1259 1297 "serde",
1260 1298 "serde_core",
@@ -1385,6 +1423,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
1385 1423 checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2"
1386 1424
1387 1425 [[package]]
1426 + name = "foldhash"
1427 + version = "0.2.0"
1428 + source = "registry+https://github.com/rust-lang/crates.io-index"
1429 + checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb"
1430 +
1431 + [[package]]
1388 1432 name = "foreign-types"
1389 1433 version = "0.3.2"
1390 1434 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1411,7 +1455,7 @@ checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742"
1411 1455 dependencies = [
1412 1456 "proc-macro2",
1413 1457 "quote",
1414 - "syn 2.0.114",
1458 + "syn 2.0.117",
1415 1459 ]
1416 1460
1417 1461 [[package]]
@@ -1456,9 +1500,9 @@ dependencies = [
1456 1500
1457 1501 [[package]]
1458 1502 name = "futures"
1459 - version = "0.3.31"
1503 + version = "0.3.32"
1460 1504 source = "registry+https://github.com/rust-lang/crates.io-index"
1461 - checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876"
1505 + checksum = "8b147ee9d1f6d097cef9ce628cd2ee62288d963e16fb287bd9286455b241382d"
1462 1506 dependencies = [
1463 1507 "futures-channel",
1464 1508 "futures-core",
@@ -1471,9 +1515,9 @@ dependencies = [
1471 1515
1472 1516 [[package]]
1473 1517 name = "futures-channel"
1474 - version = "0.3.31"
1518 + version = "0.3.32"
1475 1519 source = "registry+https://github.com/rust-lang/crates.io-index"
1476 - checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10"
1520 + checksum = "07bbe89c50d7a535e539b8c17bc0b49bdb77747034daa8087407d655f3f7cc1d"
1477 1521 dependencies = [
1478 1522 "futures-core",
1479 1523 "futures-sink",
@@ -1481,15 +1525,15 @@ dependencies = [
1481 1525
1482 1526 [[package]]
1483 1527 name = "futures-core"
1484 - version = "0.3.31"
1528 + version = "0.3.32"
1485 1529 source = "registry+https://github.com/rust-lang/crates.io-index"
1486 - checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e"
1530 + checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d"
1487 1531
1488 1532 [[package]]
1489 1533 name = "futures-executor"
1490 - version = "0.3.31"
1534 + version = "0.3.32"
1491 1535 source = "registry+https://github.com/rust-lang/crates.io-index"
1492 - checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f"
1536 + checksum = "baf29c38818342a3b26b5b923639e7b1f4a61fc5e76102d4b1981c6dc7a7579d"
1493 1537 dependencies = [
1494 1538 "futures-core",
1495 1539 "futures-task",
@@ -1509,9 +1553,9 @@ dependencies = [
1509 1553
1510 1554 [[package]]
1511 1555 name = "futures-io"
1512 - version = "0.3.31"
1556 + version = "0.3.32"
1513 1557 source = "registry+https://github.com/rust-lang/crates.io-index"
1514 - checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6"
1558 + checksum = "cecba35d7ad927e23624b22ad55235f2239cfa44fd10428eecbeba6d6a717718"
1515 1559
1516 1560 [[package]]
1517 1561 name = "futures-lite"
@@ -1528,32 +1572,32 @@ dependencies = [
1528 1572
1529 1573 [[package]]
1530 1574 name = "futures-macro"
1531 - version = "0.3.31"
1575 + version = "0.3.32"
1532 1576 source = "registry+https://github.com/rust-lang/crates.io-index"
1533 - checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650"
1577 + checksum = "e835b70203e41293343137df5c0664546da5745f82ec9b84d40be8336958447b"
1534 1578 dependencies = [
1535 1579 "proc-macro2",
1536 1580 "quote",
1537 - "syn 2.0.114",
1581 + "syn 2.0.117",
1538 1582 ]
1539 1583
Lines truncated
M Cargo.toml +3 -3
@@ -67,7 +67,7 @@ tauri-plugin-updater = "2"
67 67 rhai = { version = "1.17", features = ["sync", "serde"] }
68 68 notify = "6.0"
69 69 notify-debouncer-mini = "0.4"
70 - theme-common = { path = "../theme-common" }
70 + theme-common = { path = "../../Shared/theme-common" }
71 71 toml = "0.8"
72 72
73 73 # Enums
@@ -85,7 +85,7 @@ flate2 = "1.0"
85 85 open = "5"
86 86
87 87 # Markdown rendering + HTML sanitization
88 - docengine = { path = "../docengine" }
88 + docengine = { path = "../../Shared/docengine" }
89 89
90 90 # Filesystem
91 91 dirs = "6"
@@ -95,7 +95,7 @@ tracing = "0.1"
95 95 tracing-subscriber = { version = "0.3", features = ["env-filter"] }
96 96
97 97 # Tag standard
98 - tagtree = { path = "../tagtree" }
98 + tagtree = { path = "../../Shared/tagtree" }
99 99
100 100 # Internal crates
101 101 goingson-core = { path = "crates/core" }
@@ -0,0 +1,374 @@
1 + # GoingsOn Architecture
2 +
3 + Email, calendar, tasks in one place. Project management for individuals and small teams.
4 +
5 + A Rust-based productivity application built with Tauri 2 (Rust backend + Vanilla JS frontend), SQLite with sqlx 0.8, and a "Skeubrute" design aesthetic. 4 crates: `core` (domain models), `db-sqlite` (repository), `goingson-mcp` (Claude Desktop integration), `plugin-runtime` (Rhai plugins).
6 +
7 + ## High-Level Overview
8 +
9 + ```
10 + ┌─────────────────────────────────────────────────────────┐
11 + │ User Interface │
12 + │ ┌────────────────────────────────────────────────────┐ │
13 + │ │ Tauri Desktop (Vanilla JS) │ │
14 + │ └─────────────────────┬──────────────────────────────┘ │
15 + │ │ │
16 + │ ┌─────────────────────▼──────────────────────────────┐ │
17 + │ │ Tauri Commands (src-tauri/) │ │
18 + │ └─────────────────────┬──────────────────────────────┘ │
19 + └────────────────────────┼─────────────────────────────────┘
20 +
21 + ┌────────────────────────▼─────────────────────────────────┐
22 + │ goingson-core │
23 + │ ┌──────────┐ ┌──────────┐ ┌────────────┐ ┌────────────┐ │
24 + │ │ Models │ │Repository│ │ Urgency │ │ Parser │ │
25 + │ │ │ │ Traits │ │ Calculator │ │ (Quick-Add)│ │
26 + │ └──────────┘ └────┬─────┘ └────────────┘ └────────────┘ │
27 + └────────────────────┼─────────────────────────────────────┘
28 +
29 + ┌──────▼───────────┐
30 + │ goingson-db- │
31 + │ sqlite │
32 + │ (Desktop) │
33 + └──────────────────┘
34 +
35 + Additional crates:
36 + goingson-mcp MCP server (Claude Desktop integration)
37 + plugin-runtime Rhai plugin system (import plugins)
38 + ```
39 +
40 + ## Workspace Structure
41 +
42 + ```
43 + goingson/
44 + ├── crates/
45 + │ ├── core/ # Domain models, traits, business logic
46 + │ ├── db-sqlite/ # SQLite repository implementations
47 + │ ├── goingson-mcp/ # MCP server for Claude Desktop
48 + │ └── plugin-runtime/ # Rhai plugin system
49 + ├── src-tauri/ # Tauri desktop app (single-user)
50 + └── migrations/
51 + └── sqlite/ # SQLite schema migrations (32 files)
52 + ```
53 +
54 + ## Crate Dependencies
55 +
56 + ```
57 + goingson-desktop (src-tauri)
58 + ├── goingson-db-sqlite
59 + │ └── goingson-core
60 + ├── goingson-mcp
61 + │ └── goingson-core
62 + └── plugin-runtime
63 + └── goingson-core (for shared types)
64 + ```
65 +
66 + ## Core Crate (`crates/core/`)
67 +
68 + The core crate defines domain models and repository traits, independent of persistence.
69 +
70 + ### Modules
71 +
72 + | Module | Purpose |
73 + |--------|---------|
74 + | `models/` | Domain types (13 model files) |
75 + | `repository.rs` | Repository traits (data access contracts) |
76 + | `urgency.rs` | TaskWarrior-inspired urgency calculation algorithm |
77 + | `parser.rs` | Quick-add natural language parser |
78 + | `recurrence.rs` | Task/event recurrence logic |
79 + | `validation.rs` | Input validation trait |
80 + | `constants.rs` | Named constants for thresholds, formats |
81 + | `error.rs` | Unified CoreError type |
82 +
83 + ### Key Types
84 +
85 + ```rust
86 + // Domain entities
87 + Project, Task, Event, Email, EmailAccount, User
88 + Contact, ContactEmail, ContactPhone, SocialHandle, ContactCustomField
89 + SavedView, Annotation, Subtask, Milestone
90 + WeeklyReview, LlmSettings, BackupSettings
91 +
92 + // Enums with display/parse support
93 + ProjectType, ProjectStatus, TaskStatus, Priority, Recurrence
94 + SortDirection, SortField, TaskSortColumn
95 + ViewType, ViewFilters, BlockType
96 + EmailAuthType, LlmProviderType, MilestoneStatus
97 +
98 + // DTOs for creation/updates
99 + NewProject, NewTask, NewEvent, NewEmail
100 + UpdateProject, UpdateTask, UpdateEvent
101 +
102 + // Newtype IDs
103 + ProjectId, TaskId, EventId, EmailId, ContactId
104 + EmailAccountId, AnnotationId, SubtaskId, SavedViewId
105 + MilestoneId, CustomFieldId
106 + ```
107 +
108 + ### Repository Traits
109 +
110 + ```rust
111 + ProjectRepository, TaskRepository, EventRepository
112 + EmailRepository, EmailAccountRepository, ContactRepository
113 + SearchRepository, StatsRepository, SavedViewRepository
114 + LlmSettingsRepository, LlmCacheRepository
115 + AnnotationRepository, SubtaskRepository, MilestoneRepository
116 + WeeklyReviewRepository, BackupSettingsRepository
117 + UserRepository
118 + ```
119 +
120 + ## Database Layer (`crates/db-sqlite/`)
121 +
122 + SQLite persistence for the desktop app. Single-user, local storage. 32 migrations in `migrations/sqlite/`.
123 +
124 + ```
125 + src/
126 + ├── lib.rs # SQLite pool initialization
127 + ├── utils.rs # format_datetime, parse_uuid, email validation
128 + └── repository/
129 + ├── mod.rs # Re-exports all repositories
130 + ├── project_repo.rs
131 + ├── task_repo.rs
132 + ├── event_repo.rs
133 + ├── email_repo.rs
134 + ├── email_account_repo.rs
135 + ├── contact_repo.rs
136 + ├── user_repo.rs
137 + ├── search_repo.rs # FTS5 full-text search
138 + ├── stats_repo.rs # Dashboard aggregations
139 + ├── saved_view_repo.rs
140 + ├── llm_repo.rs # LLM settings + response cache
141 + ├── annotation_repo.rs
142 + ├── subtask_repo.rs
143 + ├── milestone_repo.rs
144 + ├── weekly_review_repo.rs
145 + └── backup_settings_repo.rs
146 + ```
147 +
148 + ## Tauri Desktop App (`src-tauri/`)
149 +
150 + Single-user desktop application.
151 +
152 + ```
153 + src/
154 + ├── main.rs # Tauri app setup, command registration
155 + ├── state.rs # AppState with repository instances
156 + ├── notifications.rs # Snooze watcher, native notifications
157 + ├── email/ # IMAP/SMTP client
158 + ├── llm/ # LLM provider clients (Ollama, OpenAI)
159 + └── commands/
160 + ├── mod.rs # Re-exports all commands
161 + ├── error.rs # Error type definitions
162 + ├── task.rs # Task CRUD, annotations, subtasks, snoozing, waiting
163 + ├── project.rs # Project management
164 + ├── event.rs # Calendar events
165 + ├── email.rs # Email CRUD, threading, archive
166 + ├── email_account.rs # Email account setup, sync interval
167 + ├── email_sync.rs # IMAP/SMTP sync orchestration
168 + ├── contact.rs # Contact CRUD, emails, phones, social handles
169 + ├── search.rs # Full-text search across all entities
170 + ├── stats.rs # Dashboard statistics
171 + ├── day_planning.rs # Time blocking
172 + ├── weekly_review.rs # Weekly review workflow
173 + ├── saved_views.rs # Custom filter views
174 + ├── milestone.rs # Milestone CRUD and reordering
175 + ├── llm.rs # LLM settings, template evaluation
176 + ├── plugin.rs # Plugin registry, hot-reload, import
177 + ├── oauth.rs # OAuth2 flows (Fastmail, Google, Microsoft)
178 + ├── export.rs # JSON, CSV, ICS export; backup/restore
179 + ├── sync.rs # Cloud sync via SyncKit
180 + ├── themes.rs # Theme list and color queries
181 + └── window.rs # Window management, compose window
182 + ```
183 +
184 + ### Command Pattern
185 +
186 + Tauri commands are async functions that:
187 + 1. Accept `State<Arc<AppState>>` for repository access
188 + 2. Deserialize input from frontend via `#[serde(rename_all = "camelCase")]`
189 + 3. Call repository methods
190 + 4. Serialize response types back to frontend
191 +
192 + ```rust
193 + #[tauri::command]
194 + pub async fn create_task(
195 + state: State<'_, Arc<AppState>>,
196 + input: TaskInput,
197 + ) -> Result<TaskResponse, String> {
198 + state.tasks
199 + .create(DESKTOP_USER_ID, new_task)
200 + .await
201 + .map(TaskResponse::from)
202 + .map_err(|e| e.to_string())
203 + }
204 + ```
205 +
206 + ## Frontend Architecture (Tauri Desktop)
207 +
208 + The desktop frontend uses vanilla JavaScript organized under the `GoingsOn` global namespace. 39 source files + 2 test files.
209 +
210 + ### Namespace Organization
211 +
212 + ```
213 + window.GoingsOn = {
214 + api: { ... }, // Tauri IPC abstraction layer
215 + state: { ... }, // Centralized state with pub/sub
216 + ui: { ... }, // Modal, toast, form utilities
217 + utils: { ... }, // HTML escaping, validation
218 +
219 + // Domain modules (IIFE-wrapped)
220 + projects: { ... },
221 + tasks: { ... },
222 + events: { ... },
223 + emails: { ... },
224 + contacts: { ... },
225 +
226 + // Feature modules
227 + savedViews: { ... },
228 + snooze: { ... },
229 + navigation: { ... },
230 + settings: { ... },
231 + app: { ... },
232 +
233 + // Infrastructure
234 + VirtualScroller, // Virtual scrolling for large lists
235 + SelectionManager, // Multi-select with shift/ctrl
236 + PaginationManager, // Page navigation
237 + };
238 + ```
239 +
240 + ### Module Pattern
241 +
242 + Each domain module is wrapped in an IIFE and exposes its public API through the namespace:
243 +
244 + ```javascript
245 + (function() {
246 + 'use strict';
247 + // Private state and helpers
248 + async function load() { ... }
249 + function openNew() { ... }
250 +
251 + // Public API
252 + GoingsOn.myModule = { load, openNew };
253 + })();
254 + ```
255 +
256 + ### Pre-computed Response Fields
257 +
258 + Rust response types include pre-computed display values so JS never calculates dates, formatting, or derived state:
259 +
260 + | Response Type | Pre-computed Fields |
261 + |--------------|---------------------|
262 + | TaskResponse | `dueFormatted`, `urgencyClass`, `isOverdue`, `isSnoozed`, `subtaskCount`, `subtaskCompleted`, `subtaskProgress` |
263 + | EventResponse | `timeFormatted`, `dateFormatted`, `isPast`, `proximityClass`, `proximityLabel` |
264 + | EmailResponse | `receivedFormatted` |
265 + | EmailAccountResponse | `lastSyncFormatted` |
266 +
267 + ### Centralized State
268 +
269 + All shared data lives in `GoingsOn.state` with reactive pub/sub:
270 +
271 + ```javascript
272 + GoingsOn.state.set('tasks', updatedTasks); // Triggers subscribers
273 + GoingsOn.state.subscribe('tasks', (newVal, oldVal) => { ... });
274 + ```
275 +
276 + ### File Organization
277 +
278 + ```
279 + src-tauri/frontend/
280 + ├── css/
281 + │ └── styles.css # Design system + all components
282 + ├── fonts/
283 + │ └── Reglo-Bold.woff2 # Display font
284 + ├── js/
285 + │ ├── goingson.js # Namespace root (window.GoingsOn)
286 + │ ├── api.js # Tauri IPC abstraction
287 + │ ├── state.js # Centralized state + pub/sub
288 + │ ├── utils.js # Escaping, validation, debounce
289 + │ ├── router.js # View routing
290 + │ ├── app.js # App initialization, menu listeners
291 + │ │
292 + │ ├── components.js # Toast, confirm dialog
293 + │ ├── components-modal.js # Modal system
294 + │ ├── form-modal.js # Form modal (openFormModal)
295 + │ ├── navigation.js # View switching, sidebar
296 + │ ├── keyboard.js # Keyboard shortcuts
297 + │ ├── selection-manager.js # Multi-select with shift/ctrl
298 + │ ├── pagination-manager.js # Page navigation
299 + │ ├── virtual-scroller.js # Virtual scrolling for large lists
300 + │ ├── context-menus.js # Right-click context menus
301 + │ ├── bulk-actions.js # Multi-select bulk operations
302 + │ ├── touch.js # Touch event handling
303 + │ ├── mobile.js # Mobile-specific behavior
304 + │ │
305 + │ ├── tasks.js # Task list, CRUD
306 + │ ├── tasks-render.js # Task rendering
307 + │ ├── tasks-kanban.js # Kanban board view
308 + │ ├── projects.js # Project list, detail, CRUD
309 + │ ├── projects-render.js # Project rendering
310 + │ ├── events.js # Event list, CRUD
311 + │ ├── emails.js # Email list, threading, CRUD
312 + │ ├── email-accounts.js # Email account management
313 + │ ├── contacts.js # Contact CRUD
314 + │ ├── contacts-render.js # Contact rendering
315 + │ │
316 + │ ├── day-planning.js # Time-blocking day planner
317 + │ ├── day-planning-render.js # Day plan rendering
318 + │ ├── weekly-review.js # Weekly review workflow
319 + │ ├── weekly-review-render.js # Weekly review rendering
320 + │ ├── snooze.js # Snooze modal + actions
321 + │ ├── settings.js # Settings, LLM config, export
322 + │ ├── settings-sync.js # Cloud sync settings
323 + │ ├── themes.js # Theme switching
324 + │ ├── export.js # Data export
325 + │ ├── import.js # Data import from JSON
326 + │ ├── llm-templates.js # LLM template evaluation
327 + │ ├── seed-data.js # Demo data seeding
328 + │ │
329 + │ └── tests/
330 + │ ├── test-runner.js # Test framework
331 + │ └── run.js # Test execution
332 + └── index.html # Entry point
333 + ```
334 +
335 + ## Data Flow
336 +
337 + ```
338 + Frontend (JS)
339 + → invoke("command_name", { args })
340 + → Tauri IPC
341 + → commands/module.rs
342 + → Repository trait method
343 + → SQLite query
344 + → Response (with pre-computed display fields) → Frontend
345 + → JS renders pre-computed values directly to DOM
346 + ```
347 +
348 + ## Key Design Decisions
349 +
350 + ### Clean Architecture
351 + - Core domain models have no dependencies on persistence
352 + - Repository traits define contracts, implementations are separate crates
353 + - Easy to swap databases or add new ones
354 +
355 + ### Vanilla Frontend
356 + - No JavaScript framework — vanilla JS with IIFE modules
357 + - All code under `GoingsOn` global namespace (no `window.*` exports)
358 + - Centralized state via `GoingsOn.state` with pub/sub reactivity
359 + - IPC via Tauri invoke
360 + - Virtual scrolling for large lists (`GoingsOn.VirtualScroller`)
361 + - Optimized for desktop-class performance
362 +
363 + ### TaskWarrior-Inspired Features
364 + - Urgency calculation algorithm
365 + - Quick-add parser with natural language
366 + - Annotations and recurring tasks
367 +
368 + ## Testing Strategy
369 +
370 + - 658 Rust tests + 48 JS tests
371 + - Unit tests in core crate for business logic
372 + - Integration tests for repository implementations
373 + - Tauri command tests
374 + - JS tests in `frontend/js/tests/`
@@ -0,0 +1,373 @@
1 + # GoingsOn -- Audit Review
2 +
3 + **Last audited:** 2026-03-28 (eleventh audit, Run 12 cross-project)
4 + **Previous audit:** 2026-03-18 (tenth audit, Run 9 cross-project)
5 + **Auditor:** Claude Opus 4.6 (automated codebase audit)
6 + **Scope:** Full workspace (`crates/core`, `crates/db-sqlite`, `crates/goingson-mcp`, `crates/plugin-runtime`, `src-tauri`, frontend JS, migrations)
7 +
8 + ---
9 +
10 + ## Overall Grade: A
11 +
12 + Run 12: ~734 tests (686 Rust + 48 JS), zero clippy warnings, zero failures. Architecture holds at A+. v0.3.0. Grade stable at A. Kanban board fix (valid task status handling). async-std unmaintained warning (upstream via async-imap). Seventh consecutive stable audit.
13 +
14 + ---
15 +
16 + ## Scorecard
17 +
18 + | Dimension | Grade | Notes |
19 + |-----------|:-----:|-------|
20 + | **Code Quality** | A | Zero clippy warnings. ~50-60 non-test `.unwrap()`/`.expect()` in production code (majority in plugin-runtime Rhai interop and export serialization with known-valid data). Consistent `CoreError`/`ApiError` chain with structured error codes. |
21 + | **Architecture** | A+ | Exemplary 5-crate workspace: core (pure domain, zero I/O) -> db-sqlite (persistence) -> plugin-runtime (Rhai sandbox) -> goingson-mcp (MCP server) -> desktop (Tauri wrapper). Repository trait pattern. Pre-computed response fields. No layer violations. |
22 + | **Testing** | A | 725 tests (677 Rust + 48 JS), 0 failures, 9 ignored. Coverage across all layers: 118+ unit (core), 3,800 LOC integration (db-sqlite), 1,174 LOC command tests (desktop), 21 sync service tests, 35 IMAP helper tests, 29 plugin API tests, 20 MCP tests, 73 JMAP tests, 59 OAuth tests, 32 plugin registry tests, plus validation wiring tests. |
23 + | **Security** | A | All SQL parameterized via sqlx bind. Sync engine table/column names from `&'static str` whitelists only. FTS5 queries escaped via `prepare_fts5_query()`. Frontend: 200+ `escapeHtml()`/`escapeAttr()` calls. OS keychain for credentials. OAuth2 + PKCE. Plugin sandbox. Email HTML sanitized (CSP meta tag + script/event handler stripping). Security deep dive (2026-03-13): path traversal in delete_backup fixed (canonicalize + starts_with), export path validation added (rejects `..` components). |
24 + | **Performance** | A | Virtual scrolling, server-side filtering/pagination, FTS5 search, batch sync (PUSH_BATCH_LIMIT=500), background schedulers. Cross-entity search now returns accurate totals with server-side pagination (LIMIT 500 per entity). |
25 + | **Documentation** | A | Module-level `//!` docs on every Rust source file. `///` doc comments on all public types and methods. JSDoc on JS modules. 3,621+ doc comments. `docs/ARCHITECTURE.md` and `docs/STYLEGUIDE.md` current. |
26 + | **Dependencies** | A | All deps pinned at workspace level. Core crate: 8 deps (zero framework deps). Desktop: 30+ (appropriate for full productivity app). `notify-debouncer-mini` confirmed in workspace deps (`Cargo.toml:68`). |
27 + | **Frontend** | A | 39 IIFE modules in `GoingsOn` namespace with `'use strict'`. Centralized `AppStateManager` with pub/sub. `GoingsOn.handle()` dispatcher. Mobile touch gestures. JS audit complete (14/14 — XSS, state mutations, dedup, cleanup). 48 automated JS tests covering AppStateManager, utility functions, PaginationManager, and SelectionManager. |
28 + | **Type Safety** | A | 11 entity ID newtypes via `define_uuid_id!` macro. Typed enums for ViewFilters status/priority, SavedView sort. `SortDirection::sql()` in db-sqlite (not core). All model structs use typed IDs. |
29 + | **Observability** | A | Structured `tracing` with EnvFilter. 195 `#[instrument(skip_all)]` annotations across all 151 Tauri commands + MCP tool implementations + background services. No request/trace ID correlation for Tauri IPC. |
30 + | **Concurrency** | A | SQLite serializes writes. `AppState` holds `Arc<dyn Repository>`. No `Mutex`/`RwLock` in application code. Background tasks via `tokio::spawn`. UNIQUE constraints on key tables. Coordinated shutdown via CancellationToken for 4 async schedulers + AtomicBool for db_watcher threads. |
31 + | **Resilience** | A | Crash-safe sync cursor persistence. `applying_remote` flag cleared on error. Background tasks continue when individual operations fail. Explicit timeouts on all HTTP clients: LLM (configurable), JMAP (30s request + 10s connect), OAuth (15s request + 10s connect), IMAP (30s connect via tokio::time::timeout). |
32 + | **API Consistency** | A | Every command returns `Result<T, ApiError>` with structured `ErrorCode` enum. Consistent pagination via `PaginatedResponse<T>`. All response types use `camelCase`. Pre-computed display fields. |
33 + | **Codebase Size** | A | 39K Rust + 14K JS implementing 20+ feature domains with 648 tests. ~2,900 lines per major feature. No dead code, no bloat. Pre-computed response pattern eliminates JS duplication. |
34 +
35 + ---
36 +
37 + ## Module Heatmap
38 +
39 + | Module | Code | Arch | Test | Security | Perf | Docs | Deps | Frontend |
40 + |--------|:----:|:----:|:----:|:--------:|:----:|:----:|:----:|:--------:|
41 + | **goingson-core** | A | A+ | A | n/a | A | A | A+ | n/a |
42 + | **goingson-db-sqlite** | A | A | A | A | A- | A- | n/a | n/a |
43 + | **goingson-desktop** | A- | A | A- | A | B+ | A | B+ | n/a |
44 + | **goingson-plugin-runtime** | A- | A | B+ | A | A | A- | n/a | n/a |
45 + | **goingson-mcp** | A | A | A- | A | A | A | A | n/a |
46 + | **JS Frontend** | A- | A | A- | A | A- | B+ | n/a | A |
47 +
48 + ### Cold Spots
49 +
50 + All previous cold spots resolved:
51 +
52 + - ~~**JMAP module (0 tests)**~~ -- 73 tests added
53 + - ~~**OAuth callback server (0 tests)**~~ -- 59 tests added
54 + - ~~**Plugin registry hot-reload (2 tests)**~~ -- 32 tests added (was 2)
55 + - ~~**LLM integration (string errors)**~~ -- typed `LlmError` enum replaces `Result<String, String>`
56 +
57 + ---
58 +
59 + ## Mandatory Surprise
60 +
61 + **The `Validate` trait is entirely dead code in production.** Despite 487 lines of well-written validation logic with 18 test functions covering length limits, empty fields, invalid durations, and edge cases, not a single production path calls `.validate()`. The commands do their own ad-hoc checks (mostly just `description.trim().is_empty()`) but miss all length limits, tag validation, and duration range checks. A user could create a task with a 10MB description. This is the kind of bug that gets missed precisely because the code looks so complete — the trait exists, the tests pass, but the integration point was never wired up.
62 +
63 + **Resolution (2026-03-13):** Validate trait now wired into the command layer. All validation rules are enforced in production. Dead code finding resolved.
64 +
65 + ### Previous Mandatory Surprise (fifth audit)
66 +
67 + **The sync engine builds SQL with `format!()` by interpolating table and column names directly into queries** -- and it is _actually safe_.
68 +
69 + In `sync_service.rs`, both `apply_upsert()` and `create_initial_snapshot()` construct SQL like:
70 +
71 + ```rust
72 + let sql = format!(
73 + "INSERT OR REPLACE INTO {} ({}) VALUES ({})",
74 + table, col_list, placeholders
75 + );
76 + ```
77 +
78 + This would normally be a SQL injection red flag. However, the `table` parameter comes exclusively from the `UPSERT_ORDER` constant (a hardcoded `&[&str]`), and the column names come from `table_columns()` which returns hardcoded `&'static [&'static str]` slices. User-supplied data (actual values) goes through `sqlx::query().bind()` parameterized binding. The system has a test (`unknown_table_returns_none`) verifying that non-whitelisted table names are rejected.
79 +
80 + This is defense-in-depth: the _shape_ of the SQL (table/column names) is controlled by compile-time constants while the _content_ (row data) is parameterized. Impressive.
81 +
82 + ---
83 +
84 + ## Strengths
85 +
86 + ### 1. Exemplary layered architecture
87 +
88 + Five crates with strictly acyclic dependencies: core (7,131 LOC, zero I/O) -> db-sqlite (5,771 LOC) -> plugin-runtime (2,419 LOC) -> goingson-mcp (2,658 LOC) -> desktop (15,529 LOC). Repository trait pattern with 15 async trait definitions. Pre-computed response fields eliminate JS duplication. No layer violations detected.
89 +
90 + ### 2. Comprehensive SQL injection and XSS prevention
91 +
92 + Every database query uses sqlx parameterized bind. Dynamic SQL in sync_service uses compile-time constant whitelists. FTS5 queries escaped via `prepare_fts5_query()`. Frontend: 200+ `escapeHtml()`/`escapeAttr()` calls across 39 JS files. Email HTML bodies stripped server-side. Plugin sandbox restricts file access.
93 +
94 + ### 3. Strong type system discipline
95 +
96 + 11 entity ID newtypes via macro prevent cross-entity ID confusion. Typed enums replace stringly-typed filter/sort fields. `CoreError` -> `ApiError` conversion chain with structured error codes. 26 public enums with `strum` derive for string conversion. `DbValue` trait for enum persistence.
97 +
98 + ### 4. Thorough test coverage at every layer
99 +
100 + 648 tests across unit (core parsers, validation, urgency, recurrence), integration (all 12 repository implementations), command (task, email, contact, event, export), sync (FK-ordering, trigger suppression), plugin (29 Rhai API binding tests), MCP (20 tool tests), JMAP (73 tests), OAuth (59 tests), and plugin registry (32 tests). Test LOC: ~7,500.
101 +
102 + ### 5. Mobile-ready architecture
103 +
104 + CSS-first responsive design with `@media (max-width: 768px)`. Touch gesture module (`touch.js`) with long-press, swipe, pull-to-refresh. Desktop-only deps gated with `cfg(not(mobile))`. iOS simulator builds working. Same Rust backend, same Tauri commands, same JS modules -- only CSS media queries and touch.js differ.
105 +
106 + ---
107 +
108 + ## Weaknesses
109 +
110 + ### 1. ~~`body_preview()` byte-slicing can panic on multi-byte UTF-8~~ (RESOLVED)
111 +
112 + Already uses `.chars().take(n)` with 18 unit tests.
113 +
114 + ### 2. ~~`list_completed_between` ignores date parameters~~ (RESOLVED)
115 +
116 + `completed_at` column added (migration 031), function now filters by date range, 4 tests.
117 +
118 + ### 3. ~~Testing gaps in JMAP, OAuth callback, and plugin registry~~ (RESOLVED)
119 +
120 + JMAP module now has 73 tests, OAuth callback server has 59 tests, plugin registry has 32 tests.
121 +
122 + ### 4. ~~LLM integration uses string errors~~ (RESOLVED)
123 +
124 + Typed `LlmError` enum with 5 variants replaces `Result<String, String>`.
125 +
126 + ---
127 +
128 + ## Competitive Comparison
129 +
130 + GoingsOn occupies a unique position as the only app combining tasks, email, calendar, contacts, and weekly review in a single offline-first native application. Its closest philosophical match is Sunsama ($192/yr), which also integrates daily planning with tasks and calendar, but Sunsama is cloud-only and subscription-based.
131 +
132 + **Key competitive advantages:**
133 + - Only app with all 5 domains integrated (tasks + email + calendar + contacts + weekly review)
134 + - Offline-first with zero cloud dependency (vs. Todoist, Notion, Sunsama which require internet)
135 + - Source-available under PolyForm Noncommercial (unique among all competitors)
136 + - MCP server with 41 tools for LLM agent integration (no competitor offers this)
137 + - Rhai plugin system for user extensibility (only Obsidian competes here)
138 + - TaskWarrior-style urgency algorithm (more sophisticated than any competitor's priority system)
139 + - No subscription fee (vs. $48-$408/yr for competitors)
140 + - Cross-platform including Linux (Things 3, Fantastical are Apple-only)
141 + - Mobile port in progress with CSS-first responsive design
142 +
143 + **Key competitive gaps:**
144 + 1. **Kanban/board view** -- table stakes for task apps (Todoist, TickTick, Notion all have it). On the roadmap.
145 + 2. **Monthly calendar view** -- universally expected. Only day plan timeline exists.
146 + 3. **External calendar sync** -- Google Calendar, Apple Calendar, CalDAV. Planned, high priority.
147 + 4. **Mobile app** -- iOS simulator builds working, Android init remaining. Competitors have mature mobile apps.
148 + 5. **Guided daily planning ritual** -- Sunsama's signature feature. GoingsOn has weekly review but no structured daily workflow.
149 +
150 + ---
151 +
152 + ## Action Items
153 +
154 + Outstanding work tracked in `docs/apps/go/todo/todo.md`.
155 +
156 + ### Resolved (sixth audit — pre-launch skeptical lens)
157 + 15. ~~**[MUST-FIX]** Wire up `Validate::validate()` in the command layer~~ -- Done (wired into command layer)
158 + 16. ~~**[MUST-FIX]** Sanitize HTML email body in `open_email_in_browser`~~ -- Done (CSP meta tag + script/event handler stripping)
159 + 17. ~~**[LOW]** Remove or deprecate `ImapClient::new()` legacy constructor~~ -- Done (removed)
160 + 18. ~~**[LOW]** Defensive `.ok_or()` on email_repo.rs:129~~ -- Done
161 + 19. ~~**[LOW]** Use `bind()` for LIMIT/OFFSET~~ -- Done (parameterized binds in task_repo.rs)
162 +
163 + ### All resolved (previous audits)
164 + 1. ~~**[Bug]** Fix `body_preview()` UTF-8 panic~~ -- already uses `.chars().take(n)` with 18 tests
165 + 2. ~~**[Performance]** Batch dashboard stats queries~~ -- already uses single query with 6 subqueries
166 + 3. ~~**[Clippy]** Fix `clone_on_copy` in goingson-mcp~~ -- fixed (`task_impl.rs:271`)
167 + 4. ~~**[Testing]** Add integration tests for `search_repo`~~ -- 15 tests added
168 + 5. ~~**[Testing]** Add integration tests for `contact_repo`~~ -- 18 tests added
169 + 6. ~~**[Logic bug]** `list_completed_between` date filtering~~ -- `completed_at` column added (migration 031), 4 tests
170 + 7. ~~**[Testing]** MCP server tool tests~~ -- 20 integration tests added
171 + 8. ~~**[Testing]** Sync service tests~~ -- 21 unit tests
172 + 9. ~~**[Testing]** Plugin API tests~~ -- 29 tests covering all exposed types
173 + 10. ~~**[Testing]** IMAP HTML helper tests~~ -- 35 tests on pure functions
174 + 11. ~~**[Refactor]** Convert sync service to typed errors~~ -- `Result<_, CoreError>` throughout
175 + 12. ~~**[Refactor]** Move `sql_column()` out of core~~ -- relocated to db-sqlite
176 + 13. ~~**[Docs]** Add `//!` docs to `smtp_client.rs`~~ -- done
177 + 14. ~~**[Frontend]** Add section markers to `styles.css`~~ -- 60 numbered sections with TOC
178 +
179 + New items filed in `docs/apps/go/todo/todo.md`:
180 + - ~~Add unit tests for JMAP module (854 LOC, 0 tests)~~ -- 73 tests added
181 + - ~~Add tests for OAuth callback server (309 LOC, 0 tests)~~ -- 59 tests added
182 + - ~~Add tests for plugin registry hot-reload (300 LOC, 2 tests)~~ -- 32 tests added
183 + - Add doc comment to sync_service.rs explaining format!() SQL safety pattern
184 + - ~~LLM integration: use typed errors instead of Result<String, String>~~ -- typed LlmError enum added
185 + - Verify applying_remote flag cleared on startup (crash recovery)
186 +
187 + ### Security Deep Dive (2026-03-13) — Complete (2/2)
188 +
189 + - **Path traversal in delete_backup:** `commands/export.rs` — `delete_backup()` now uses `canonicalize()` on both backup directory and target path, then verifies `canonical_path.starts_with(&canonical_backup_dir)`
190 + - **Export path validation:** `commands/export.rs` — `validate_export_path()` helper added, rejects `..` components; called at top of `export_json`, `export_tasks_csv`, `export_events_ics`, and `restore_backup`
191 +
192 + ### JS Audit Remediation (2026-03-11) — Complete (14/14)
193 +
194 + All JS audit findings resolved:
195 + - **Critical (2):** escapeAttr() on 25 onclick handlers across 7 files, escapeHtml() on backend labels in innerHTML
196 + - **Medium (6):** Event status computation moved to Rust (`get_event_status_indicator` command, pre-computed EventResponse fields), project form dedup (delegated to tasks.openNewForProject/events.openNewForProject), state mutation migration (16 fixes to GoingsOn.state.set()), email account form dedup (buildAccountFormHtml()), IMAP/SMTP error escaping
197 + - **Low (6):** Dead matchesFilters() removed, window.GO alias removed, dynamic version via Tauri app.getVersion(), confirm() → confirmDelete() (5 calls), contacts filter state migrated to GoingsOn.state, 100ms sleep removed
198 +
199 + ---
200 +
201 + ## Metrics Over Time
202 +
203 + | Audit Date | Rust LOC | Rust Files | Tests | Tests/KLOC | Clippy Warnings | Overall |
204 + |------------|----------|-----------|-------|-----------|----------------|---------|
205 + | 2026-02-27 | ~30K | ~110 | 234 | 7.8 | 0 | A- |
206 + | 2026-02-28 | ~30K | ~110 | 289 | 9.6 | 0 | A- |
207 + | 2026-03-01 | ~33K | ~130 | 338 | 10.2 | 0 | A |
208 + | 2026-03-02 | ~35K | ~140 | 435 | 12.4 | 0 | A |
209 + | 2026-03-11 | 39,183 | 152 | 485 | 12.4 | 0 | A |
210 + | 2026-03-13 | ~39K | ~152 | 658 | ~16.9 | 0 | A |
211 + | 2026-03-16 | 44K | ~152 | 725 | ~16.5 | 0 | A |
212 + | 2026-03-18 | 44K | ~152 | 725 | ~16.5 | 0 | A |
213 + | 2026-03-28 | ~44K | ~152 | ~734 | ~16.7 | 0 | A |
214 +
215 + ---
216 +
217 + ## Build Verification
218 +
219 + ```
220 + cargo check --workspace PASS
221 + cargo test --workspace 648 passed, 0 failed, 9 ignored
222 + cargo clippy --workspace 0 warnings
223 + ```
224 +
225 + ---
226 +
227 + ## Changes Since Last Audit
228 +
229 + **Previous audit:** 2026-03-16 (seventh audit, Run 6)
230 +
231 + ### Eleventh audit (2026-03-28, Run 12 cross-project)
232 + - **Test count:** ~734 (686 Rust + 48 JS). 0 clippy warnings. 0 failures.
233 + - **Grade:** A (maintained). v0.3.0.
234 + - **Code change:** Kanban board fix — invalid task status now silently dropped instead of crashing. Minor but correct.
235 + - **Dependency advisory:** async-std unmaintained (RUSTSEC-2025-0052, warning) — upstream via async-imap, no alternative available.
236 + - **Mandatory surprise:** None. Previous surprises (dead Validate trait, format!() SQL safety) both resolved.
237 + - **No new findings.** All previous items remain resolved.
238 +
239 + ### Tenth audit (2026-03-18, Run 9 cross-project)
240 + - **Test count:** 725 (677 Rust + 48 JS). 0 clippy warnings. 0 failures.
241 + - **Grade:** A (maintained). v0.3.0.
242 + - **Release build:** macOS DMG signed+notarized, verified with codesign + spctl.
243 + - **No new findings.** All previous items remain resolved. Validate trait wired. Sync engine safe. All cold spots closed.
244 + - **Mandatory surprise:** None. Previous surprises (dead Validate trait, format!() SQL safety) both resolved.
245 +
246 + ### Post-Run 8 fixes (2026-03-17)
247 + - **Clippy:** Fixed 8 warnings across 5 files: `approx_constant` (api.rs), `bool_assert_comparison` (api.rs ×2, registry.rs ×2), `unnecessary_get_then_check` (registry.rs ×2), `items_after_test_module` (imap_client.rs, jmap/email.rs, jmap/session.rs)
248 + - **Deps:** `time` crate bumped 0.3.46 → 0.3.47 (fixes RUSTSEC-2026-0009 stack exhaustion DoS)
249 +
250 + **Earlier audit:** 2026-03-11 (fifth audit)
251 +
252 + ### Concurrency Upgrade (2026-03-13)
253 + - **Concurrency:** A- -> A
254 + - Coordinated shutdown via CancellationToken for 4 async schedulers + AtomicBool for db_watcher threads. All background tasks now stop cleanly on app exit via RunEvent::Exit handler.
255 +
256 + ### Observability Upgrade (2026-03-13)
257 + - **Observability:** A- -> A
258 + - Added 195 `#[instrument(skip_all)]` annotations across 28 files
259 + - Coverage: all 144 Tauri commands (20 command files), 40 MCP tool implementation methods (5 impl files), 3 email_sync background functions, plus existing state/notifications instrumentation
260 + - `use tracing::instrument;` import added to each file
261 + - `cargo check --workspace` passes clean
262 +
263 + ### Adversarial Test Audit (2026-03-13)
264 +
265 + **Test count:** 648 -> 658 (+10 tests)
266 +
267 + Key changes:
268 + - **CRITICAL fix:** Weekly review timeline used `created_at` instead of `completed_at` — timeline showed task creation dates, not completion dates. Fixed in both repository query and test assertions.
269 + - **HIGH fix:** Completed/deleted tasks could be snoozed — added status check at repository level to reject snoozing non-pending/non-started tasks.
270 + - **HIGH fix:** Recurring task completion copied stale urgency from overdue parent — now recalculates urgency with fresh `calculate_urgency()` call instead of inheriting parent's inflated urgency score.
271 + - **HIGH fix:** MCP `create_task` skipped validation — added `new_task.validate()` call to enforce length limits, tag validation, and duration range checks.
272 + - **API improvement:** Search now returns `(Vec<SearchResultItem>, usize)` tuple for accurate total counts, enabling proper pagination UI.
273 +
274 + All fixes committed with test coverage. Zero regressions detected.
275 +
276 + ### Seventh audit (2026-03-16, Run 6 cross-project)
277 + - **Test count:** 658 -> 725 (+67 tests, 677 Rust + 48 JS)
278 + - **Grade:** A (maintained). No new findings above LOW.
279 + - **Rust LOC:** 44,007 (up from ~39K)
280 + - **Mandatory surprise:** ApiError system in commands/error.rs — machine-readable ErrorCode enum, 3 extension traits (OptionNotFound, OptionApiError, ResultApiError), full CoreError->ApiError conversion — Impressive
281 + - **Previous items verified:** All previous remediated items confirmed intact.
282 +
283 + ### Sixth audit (2026-03-13, pre-launch skeptical lens)
284 + - **Grade:** A -> A- -> A. Two must-fix findings found and resolved.
285 + - **Test count:** 485 -> 648 (+163 tests)
286 + - **New findings:** Validate trait never called in production (dead code), open_email_in_browser XSS, ImapClient::new() legacy constructor, email_repo expect in production.
287 + - **Mandatory surprise:** Dead Validate trait — genuine issue, now resolved.
288 + - **Previous items verified:** All 14 prior remediated items confirmed intact.
289 +
290 + **Post-audit remediation (2026-03-13):**
291 + - Grade: A- -> A. Both must-fix items resolved.
292 + - Validate trait wired into command layer (no longer dead code)
293 + - Email HTML sanitization added (CSP + script stripping)
294 + - ImapClient::new() removed, .expect() replaced with .ok_or(), LIMIT/OFFSET parameterized
295 + - All 4 cold spots resolved: JMAP (73 tests), OAuth (59 tests), plugin registry (32 tests), LLM typed errors
296 + - Test count: 485 -> 648 (+163 tests)
297 +
298 + ### What improved (fifth audit)
299 + - Test count: 435 -> 485 (+50 tests)
300 + - Sync service now has 21 unit tests (was 6) covering FK-ordered upsert/delete, trigger suppression, column whitelists, push/pull logic
301 + - Mobile port advanced: iOS simulator running, touch gestures wired, interaction wiring complete
302 + - MCP tool count: 16 -> 41 tools
303 + - Codebase grew from ~35K to 39,183 Rust LOC while maintaining quality
304 +
305 + ### What regressed
306 + - Nothing. All previous fixes remain in place. Zero clippy warnings. Zero test failures.
307 +
308 + ### New issues found (all resolved post-audit)
309 + - ~~JMAP module (854 LOC) has zero tests~~ -- 73 tests added
310 + - ~~OAuth callback server (309 LOC) has zero tests~~ -- 59 tests added
311 + - ~~Plugin registry hot-reload (300 LOC) has only 2 tests~~ -- 32 tests added
312 + - ~~LLM integration uses `Result<String, String>` instead of typed errors~~ -- typed LlmError enum added
313 + - `applying_remote` flag should be verified cleared on startup for crash recovery (cross-project finding from audiofiles audit)
314 + - Sync engine `format!()` SQL pattern is safe but lacks documentation explaining why
315 +
316 + ### Still open (2 items)
317 + - OAuth token manager tests (token refresh flows, keychain storage)
318 + - Full IMAP client integration tests (MIME parsing and folder ops -- pure function helpers tested)
319 + - ~~JS frontend has no automated tests~~ -- 48 JS tests added (AppStateManager, utils, PaginationManager, SelectionManager)
320 +
321 + ### Resolved
322 + - ~~Move `notify-debouncer-mini` to workspace deps~~ -- confirmed already in workspace deps (`Cargo.toml:68`)
323 + - ~~Add explicit timeouts to JMAP/OAuth/IMAP clients~~ -- 30s/15s request + 10s connect timeouts added
324 +
325 + ---
326 +
327 + ## Audit History
328 +
329 + ### First audit (2026-02-27)
330 + - Initial review. 234 tests. Grade: A-. Found body_preview UTF-8 issue (later confirmed safe), list_completed_between bug, stats query concern (later confirmed efficient).
331 +
332 + ### Second audit (2026-02-28)
333 + - Fixed tag search bug. Added 30 tests (contact_repo, search_repo). 289 tests. Grade: A-.
334 +
335 + ### Third audit (2026-02-28)
336 + - Theme system rewrite. Minor findings (smtp_client docs, notify-debouncer-mini). Grade: A-.
337 +
338 + ### Fourth audit (2026-03-01)
339 + - Full fresh audit. MCP tests added, list_completed_between fixed, 49 new tests. Grade: A- -> A. Found sync_service, IMAP, OAuth token manager, plugin API, CSS, sql_column() issues.
340 +
341 + ### Cleanup phase (2026-03-02)
342 + - All fourth-audit findings resolved. +97 tests (435 total). Sync service typed errors, sql_column() relocated, CSS sections, SMTP docs, plugin API tests, IMAP helper tests.
343 +
344 + ### Type safety phase (2026-03-02)
345 + - 11 entity ID newtypes. Stringly-typed fields replaced with enums. Type Safety: A- -> A.
346 +
347 + ### Fifth audit (2026-03-11)
348 + - Full fresh audit. 485 tests. Grade: A (maintained). Mobile port near-complete. New cold spots: JMAP (0 tests), OAuth callback (0 tests), plugin registry (2 tests), LLM string errors. Mandatory surprise: sync engine format!() SQL safety.
349 +
350 + ### Sixth audit (2026-03-13)
351 + - Pre-launch skeptical lens. 648 tests. Grade: A- -> A (post-remediation). Found dead Validate trait and email HTML XSS (both must-fix, both resolved same day). All 4 cold spots from fifth audit resolved. +163 tests.
352 +
353 + ---
354 +
355 + ## Documentation Review
356 +
357 + **Last reviewed:** 2026-03-04 (first doc audit)
358 +
359 + ### Overall Doc Grade: B+
360 +
361 + Good coverage of architecture and style guide. CLAUDE.md GO section is thorough and accurate. No public-facing docs to worry about. Main gaps: description.md is a placeholder, and MCP_test.md is test scaffolding that could be removed.
362 +
363 + ### Document Heatmap
364 +
365 + | Document | Status | Last Verified | Notes |
366 + |----------|:------:|:-------------:|-------|
367 + | CLAUDE.md (GO section) | Current | 2026-03-04 | Accurate to codebase |
368 + | docs/ARCHITECTURE.md | Current | 2026-03-04 | Accurate to codebase |
369 + | docs/STYLEGUIDE.md | Current | 2026-03-04 | Skeubrute design system |
370 + | docs/description.md | Placeholder | 2026-03-04 | Intentional placeholder |
371 + | docs/competition.md | Current | 2026-03-04 | Competitive analysis |
372 + | docs/human_testing.md | Current | 2026-03-04 | Manual QA checklist |
373 + | docs/MCP_test.md | Low priority | 2026-03-04 | Test artifact, may not need to persist |
@@ -0,0 +1,314 @@
1 + # GoingsOn -- Competitive Analysis
2 +
3 + Last updated: 2026-02-27
4 +
5 + ## Positioning
6 +
7 + GoingsOn is the only app that combines tasks, email, calendar, contacts, and weekly review in a single offline-first native application. Every competitor covers 1-2 of these domains. Built with Tauri 2 (Rust backend, vanilla JS frontend, SQLite), it targets independent workers who want a fast, offline-capable workspace without SaaS lock-in.
8 +
9 + The core advantage is integration depth (tasks + email + calendar + contacts + projects in one local-first app) combined with privacy (no server, no tracking, zero-knowledge sync) and extensibility (Rhai plugins, MCP server). No single competitor matches this combination. In a market where annual subscription costs range from $48 to $408, GoingsOn ships free and source-available.
10 +
11 + ## Pricing Comparison
12 +
13 + | App | Price | Model |
14 + |-----|-------|-------|
15 + | **GoingsOn** | **Free** | Source-available, no subscription |
16 + | TickTick Premium | ~$28-36/yr | Subscription |
17 + | Fantastical | ~$40/yr | Subscription |
18 + | Todoist Pro | $48/yr | Cloud subscription |
19 + | Obsidian Sync | $48/yr | Optional sync add-on |
20 + | Spark Premium | $60/yr | Subscription |
21 + | Things 3 | ~$80 | One-time purchase (Apple only) |
22 + | Notion Plus | $120/yr | Cloud subscription |
23 + | Sunsama | $192/yr | Cloud subscription |
24 + | Akiflow | $228/yr | Cloud subscription |
25 +
26 + ## Feature Matrix
27 +
28 + | Feature | GO | Todoist | Things 3 | TickTick | Notion | Obsidian | Fantastical | Spark | Sunsama | Akiflow |
29 + |---------|:--:|:------:|:--------:|:--------:|:------:|:--------:|:-----------:|:-----:|:-------:|:-------:|
30 + | **Tasks** | Yes | Yes | Yes | Yes | Yes | Plugin | Basic | No | Yes | Yes |
31 + | **Email client** | Yes | No | No | No | No | No | No | Yes | Partial | Partial |
32 + | **Calendar** | Yes | Partial | Read-only | Yes | Basic | Plugin | Yes | No | Yes | Yes |
33 + | **Contacts** | Yes | No | No | No | No | No | No | No | No | No |
34 + | **Weekly review** | Yes | No | No | No | No | No | No | No | Yes | No |
35 + | **Offline-first** | Yes | No | Yes | No | Limited | Yes | Yes | No | No | No |
36 + | **Local data** | Yes | No | Partial | No | No | Yes | Partial | No | No | No |
37 + | **Source-available** | Yes | No | No | No | No | No | No | No | No | No |
38 + | **Plugin system** | Yes | No | No | No | API | Yes | No | No | No | No |
39 + | **MCP/LLM tools** | Yes | No | No | No | AI built-in | Plugin | No | AI built-in | No | AI built-in |
40 + | **Urgency scoring** | Yes | 4 levels | No | No | No | No | No | No | No | No |
41 + | **Cross-platform** | Yes | Yes | Apple only | Yes | Yes | Yes | Apple+Win | Yes | Yes | Mac/Win |
42 + | **Linux** | Yes | Yes | No | Yes | Yes | Yes | No | No | No | No |
43 + | **Mobile** | In progress | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Web only |
44 + | **AI features** | LLM templates | Yes | No | No | Yes | No | No | Yes | Planned | Yes |
45 + | **Team collab** | No | Yes | No | No | Yes | No | No | Yes | Yes | No |
46 + | **Free tier** | Yes | Yes | No | Yes | Yes | Yes | Limited | Yes | No | No |
47 +
48 + ## Competitor Deep Dives
49 +
50 + ### 1. Todoist
51 +
52 + **Task management SaaS with natural language input, collaboration, and AI assistant.**
53 +
54 + Pricing: Free (5 projects) | Pro $4/mo ($48/yr) | Business $6-10/user/mo
55 +
56 + | Feature GoingsOn Lacks | Notes |
57 + |------------------------|-------|
58 + | Kanban board view | Drag tasks between columns; useful for visual workflows |
59 + | Location-based reminders | Triggers reminders when arriving/leaving a location `[DATA-HUNGRY]` |
60 + | Karma gamification (points, streaks, levels) | Productivity scoring from Beginner to Enlightenment `[BLOAT]` |
61 + | Real-time collaboration (shared projects, task comments, assignments) | Multi-user shared projects with task delegation |
62 + | AI voice-to-task (Todoist Ramble) | Speak naturally, AI extracts tasks/dates/details `[DATA-HUNGRY]` |
63 + | AI task suggestions & auto-breakdown | AI suggests subtasks, rewrites vague tasks, recommends next steps `[DATA-HUNGRY]` |
64 + | Activity log / audit history | Full history of all changes across projects |
65 + | Vacation mode (protects streaks) | Pauses gamification during time off `[BLOAT]` |
66 + | Web app | Full browser-based access with no install |
67 + | Template gallery | Pre-built project templates for common workflows |
68 + | Urgent reminders (iOS full-screen alarm) | Persistent alarm that overrides Do Not Disturb `[INVASIVE]` |
69 +
70 + ### 2. Things 3
71 +
72 + **Elegant GTD-style task manager for Apple platforms. One-time purchase.**
73 +
74 + Pricing: Mac $49.99 | iPhone $9.99 | iPad $19.99 (one-time, no subscription)
75 +
76 + | Feature GoingsOn Lacks | Notes |
77 + |------------------------|-------|
78 + | Areas (high-level life categories) | Group projects under areas like "Work", "Personal", "Health" |
79 + | Today / This Evening split | Separate morning and evening task sections within the day |
80 + | Logbook (completed task archive) | Browsable archive of everything you've finished |
81 + | Someday list | GTD "Someday/Maybe" list for non-urgent ideas |
82 + | Quick Entry with project/heading targeting | System-wide shortcut to add tasks directly into a specific heading |
83 + | Headings within projects | Visual section dividers within a project task list |
84 + | Apple Watch app | Task management from the wrist |
85 + | Apple Shortcuts / URL scheme | Deep automation via Shortcuts and x-callback-url |
86 + | Magic Plus button (context-aware) | "+" button behavior changes based on current view |
87 + | Mail-to-Things (forward emails as tasks) | Forward an email to a special address to create a task |
88 + | Type-to-filter in any list | Start typing to instantly filter the visible list |
89 +
90 + ### 3. TickTick
91 +
92 + **All-in-one task manager with calendar, habits, Pomodoro timer, and Kanban.**
93 +
94 + Pricing: Free (9 lists, 99 tasks/list) | Premium ~$28-36/yr ($2.80/mo)
95 +
96 + | Feature GoingsOn Lacks | Notes |
97 + |------------------------|-------|
98 + | Habit tracker | Daily habit tracking with streaks and completion charts |
99 + | Pomodoro / focus timer | Built-in countdown and stopwatch with session tracking |
100 + | White noise / ambient sounds | Background sounds (rain, cafe, nature) during focus sessions `[BLOAT]` |
101 + | Eisenhower Matrix view | Four-quadrant urgent/important grid view |
102 + | Kanban board view | Column-based task organization |
103 + | Multiple calendar views (5 types) | Day, 3-day, week, month, and agenda calendar views |
104 + | Calendar subscription (read external) | Subscribe to external calendars (read-only) |
105 + | Task duration estimates with stats | Estimate time per task, track actual vs estimated |
106 + | Achievement badges | Gamification rewards for productivity milestones `[BLOAT]` |
107 + | Smart date parsing in descriptions | Detects dates within task descriptions |
108 + | Web app | Browser-based access |
109 + | Apple Watch / Wear OS | Wrist-based task management |
110 + | Widgets (iOS/Android/desktop) | Home screen widgets showing tasks and calendar |
111 +
112 + ### 4. Notion
113 +
114 + **Workspace combining docs, databases, wikis, project management, and AI agents.**
115 +
116 + Pricing: Free (personal) | Plus $8-10/mo | Business $20/user/mo | Enterprise custom
117 +
118 + | Feature GoingsOn Lacks | Notes |
119 + |------------------------|-------|
120 + | Freeform documents / pages | Rich-text documents with nested blocks and embeds |
121 + | Relational databases (20+ property types) | Structured data with relations, rollups, formulas, filters |
122 + | 6 database views (table, board, timeline, calendar, gallery, list) | Multiple visual layouts for the same data |
123 + | Wiki / knowledge base | Team wiki with verified pages and breadcrumb navigation |
124 + | AI agents (autonomous multi-step workflows) | Agent performs 20min of autonomous work across hundreds of pages `[DATA-HUNGRY]` |
125 + | Automations (trigger-based workflows) | If-then automations on database changes |
126 + | Forms builder | Create forms that feed into databases |
127 + | Sites (publish pages as website) | Turn Notion pages into public websites |
128 + | Template gallery (thousands) | Massive community template ecosystem |
129 + | Real-time collaboration (multiplayer editing) | Multiple users edit the same page simultaneously |
130 + | Web app | Full browser-based access |
131 + | API (public REST) | Third-party integrations via public API |
132 + | Embeds (50+ services) | Embed Figma, Loom, Google Maps, Miro, etc. inline |
133 + | Comments and mentions | @mention users, threaded comments on blocks |
134 + | Conditional database coloring | Color rows/cells based on formula conditions |
135 + | People directory | Auto-built team directory from workspace members `[BLOAT]` |
136 + | Version history (7-90 days by plan) | Page-level version history with restore |
137 +
138 + ### 5. Spark Mail
139 +
140 + **Smart email client with AI writing, inbox triage, and team collaboration.**
141 +
142 + Pricing: Free (basic) | Premium $4.99/mo ($59.99/yr) | Team $6.99/user/mo
143 +
144 + | Feature GoingsOn Lacks | Notes |
145 + |------------------------|-------|
146 + | Smart Inbox (auto-categorization) | Auto-sorts into Personal, Notifications, Newsletters `[DATA-HUNGRY]` |
147 + | Gatekeeper (unknown sender blocking) | Holds first-time senders in a queue for approval |
148 + | AI email compose / rephrase / translate | AI drafts, rewrites, and translates emails `[DATA-HUNGRY]` |
149 + | AI email summarization | Summarize long threads in one click `[DATA-HUNGRY]` |
150 + | My Writing Style (AI learns your tone) | AI mimics your personal writing style `[DATA-HUNGRY]` |
151 + | Send Later (scheduled send) | Compose now, send at a specified time |
152 + | Email signatures (rich, multiple) | Multiple formatted signatures, auto-switch per account |
153 + | Shared team inbox | Multiple team members manage one inbox |
154 + | Shared drafts (real-time co-editing) | Collaborate on email drafts in real time |
155 + | Email assignment to team members | Assign emails to colleagues with status tracking |
156 + | Smart notifications (only for important) | Only notifies for emails from real people, not newsletters `[DATA-HUNGRY]` |
157 + | Priority sender badges | Visual indicator for VIP contacts |
158 + | Newsletter digest | Groups newsletters into a single digest |
159 + | Quick replies (one-tap responses) | Suggested short responses at the bottom of emails |
160 + | Follow-up reminders | Automatic reminders when sent emails get no reply |
161 + | Email pin | Pin important emails to the top of inbox |
162 +
163 + ### 6. Fantastical
164 +
165 + **Premium calendar app with natural language, scheduling proposals, and weather.**
166 +
167 + Pricing: Free (limited) | Premium ~$3.33/mo ($40/yr) | Team pricing available
168 +
169 + | Feature GoingsOn Lacks | Notes |
170 + |------------------------|-------|
171 + | Calendar sets (grouped calendar toggling) | Switch between "Work" and "Home" calendar groups with one click |
172 + | Location-based calendar sets | Auto-switch calendar set when arriving/leaving a location `[DATA-HUNGRY]` |
173 + | Weather forecast in calendar | 10-day AccuWeather forecast inline in calendar views `[BLOAT]` |
174 + | Meeting/scheduling proposals | Send event proposals with multiple time options to invitees |
175 + | Conference call auto-detection | Auto-detects Zoom/Teams/Meet links and adds join buttons |
176 + | Conference call auto-creation | Automatically adds video call links to scheduled events |
177 + | Travel time estimates | Shows travel time between events on the calendar |
178 + | Interesting calendars (sports, TV, holidays) | Subscribe to curated event calendars `[BLOAT]` |
179 + | Apple Watch app | Calendar on the wrist |
180 + | Apple Vision Pro support | Spatial calendar in visionOS |
181 + | Multiple calendar views (day/week/month/quarter/year) | More granular view options including quarter and year |
182 + | Availability sharing (Openings) | Share available time slots via link for others to book |
183 + | Task integration (Apple Reminders, Todoist) | Show tasks from external task apps on the calendar |
184 + | Forward-to-Fantastical (email to event) | Forward an email to create a calendar event automatically |
185 + | Date & time proposals in templates | Scheduling templates with reusable configurations |
186 +
187 + ### 7. Obsidian
188 +
189 + **Local-first markdown knowledge base with graph view and 2700+ community plugins.**
190 +
191 + Pricing: Free (core app) | Sync $4/mo | Publish $8/site/mo | Catalyst $25 one-time
192 +
193 + | Feature GoingsOn Lacks | Notes |
194 + |------------------------|-------|
195 + | Freeform markdown documents | Long-form writing with wiki-style linking |
196 + | Graph view (knowledge visualization) | Interactive visual map of note connections |
197 + | Backlinks (bidirectional linking) | Every note shows what links to it automatically |
198 + | Canvas (infinite whiteboard) | Spatial arrangement of notes, images, and links |
199 + | Daily notes | Auto-created daily journal entries |
200 + | 2700+ community plugins | Massive extensibility ecosystem |
201 + | Dataview (database queries on markdown) | SQL-like queries across your notes |
202 + | Templater (advanced templates) | Dynamic templates with JavaScript logic |
203 + | Local markdown files (open format) | Plain .md files in a folder, readable by any editor |
204 + | Publish (notes as website) | Publish notes as a static website |
205 + | Excalidraw (drawing/diagramming) | Built-in whiteboard via plugin |
206 + | Vim mode | Native Vim keybindings in the editor |
207 + | Community themes (hundreds) | Massive theme ecosystem |
208 + | CLI tool | Command-line access to vaults (new in 2026) |
209 +
210 + ### 8. Sunsama
211 +
212 + **Guided daily planner that pulls tasks from external tools into a timeboxed schedule.**
213 +
214 + Pricing: $16/mo annually ($192/yr) | $20/mo monthly | No free plan
215 +
216 + | Feature GoingsOn Lacks | Notes |
217 + |------------------------|-------|
218 + | Guided daily planning ritual (multi-step) | Step-by-step morning workflow: review yesterday, pick today's tasks, timebox |
219 + | Daily shutdown ritual | Guided end-of-day reflection and task rollover |
220 + | Focus mode / focus timer | Single-task focus mode with timer (Pomodoro optional) |
221 + | Task time estimates with actuals tracking | Estimate task duration, compare to actual time spent |
222 + | Automatic timeboxing (planned) | AI auto-schedules tasks based on priority and availability `[DATA-HUNGRY]` |
223 + | Pull tasks from external tools | Import from Asana, Trello, Jira, ClickUp, Notion, Linear, GitHub |
224 + | Pull tasks from Slack/Teams messages | Turn chat messages into tasks `[DATA-HUNGRY]` |
225 + | Gmail/Outlook email-to-task (native) | Pull emails as tasks from integrated email accounts |
226 + | Daily Slack/Teams standup post | Auto-post your daily plan to a team channel |
227 + | Workload guardrails | Warns when you've scheduled more than your target hours |
228 + | Drag tasks between days | Move unfinished tasks to future days visually |
229 + | Weekly analytics | Time spent per day/week with trend visualization |
230 + | Theme days | Label days with a focus theme (e.g., "Deep Work Monday") |
231 + | Unified task view across integrations | Single list pulling from 10+ external tools |
232 +
233 + ## Common Missing Features
234 +
235 + Features that appear in 3+ competitors and GoingsOn currently lacks.
236 +
237 + ### Worth Adding
238 +
239 + | Feature | Competitors | Reasoning |
240 + |---------|-------------|-----------|
241 + | **Kanban / board view** | Todoist, TickTick, Notion, Obsidian (plugin) | Visual alternative to list/table views. Low complexity, high utility for project-oriented users. Could be a project-level view option. |
242 + | **Apple Watch app** | Things 3, TickTick, Fantastical | Quick task capture and glanceable agenda from the wrist. Tauri 2 doesn't target watchOS natively, so this would be a separate Swift micro-app. Post-launch. |
243 + | **Task time estimates with tracking** | TickTick, Sunsama, Todoist (duration) | GoingsOn already has time blocking with duration. Adding estimate-vs-actual tracking is a small extension with real value for freelancers billing by the hour. |
244 + | **Widgets (iOS/Android/desktop)** | TickTick, Things 3, Fantastical, Notion | Home screen widgets for today's tasks and upcoming events. Requires native widget code per platform. Post-mobile-launch. |
245 + | **Template gallery / starter templates** | Todoist, Notion, TickTick | Ship a small set of built-in project templates (e.g., "Freelance Project", "Content Pipeline", "Job Search"). Not a marketplace, just bundled starter configs. |
246 + | **External calendar sync (Google/Apple)** | Fantastical, TickTick, Sunsama, Notion | Already planned. Google Calendar, Apple Calendar, and CalDAV sync are on the roadmap. High priority for launch. |
247 + | **Send Later (scheduled email send)** | Spark, (Todoist has scheduled tasks) | Simple to implement -- queue outbound email with a send-at timestamp. Useful for timezone-aware communication. |
248 + | **Multiple calendar views (month/quarter/year)** | Fantastical, TickTick, Notion | GoingsOn has a day plan timeline. A month view is the most obvious gap. Quarter/year views are lower priority. |
249 +
250 + ### Consider
251 +
252 + | Feature | Competitors | Reasoning |
253 + |---------|-------------|-----------|
254 + | **Focus / Pomodoro timer** | TickTick, Sunsama, Obsidian (plugin) | Natural fit alongside time blocking and day plan. Keep it simple: a countdown timer linked to a task, no gamification. |
255 + | **Activity log / history** | Todoist, Notion (version history), Spark | An audit trail of task/project changes. Useful for accountability and undo. Could be implemented locally in SQLite with minimal overhead. |
256 + | **Guided daily planning ritual** | Sunsama, (Things 3 Today/Evening), TickTick | GoingsOn has weekly review but no daily planning ritual. A lightweight morning workflow (review overdue, pick today's tasks, timebox) would complement the existing weekly review without adding bloat. |
257 +
258 + ### Skip
259 +
260 + | Feature | Competitors | Reasoning |
261 + |---------|-------------|-----------|
262 + | **Web app** | Todoist, TickTick, Notion, Sunsama | Contradicts local-first architecture and privacy model. Tauri desktop + mobile covers the target audience. A web app would require a server and undermine the offline-first value prop. |
263 + | **Real-time collaboration** | Todoist, Notion, Spark, Sunsama | GoingsOn targets independent workers, not teams. Collaboration adds massive complexity (CRDT/OT, permissions, presence) with minimal value for the target user. |
264 + | **Freeform documents / notes** | Notion, Obsidian, (Things 3 has task notes) | GoingsOn has task annotations and descriptions. Full document editing is a massive scope expansion that competes with dedicated tools. Better to integrate with Obsidian via plugin than to rebuild a notes system. |
265 + | **AI writing / compose assistance** | Todoist, Spark, Notion | GoingsOn already has LLM templates and AI-Fill. Adding full AI compose for emails would require sending email content to a third party, conflicting with the privacy-first model. The existing local LLM approach (Ollama) is the right path. |
266 +
267 + ## What We Offer That Competitors Don't
268 +
269 + - **Only app with all 5 domains** -- tasks + email + calendar + contacts + weekly review in one native app. No other tool does this. Deep cross-linking between all entity types (email-to-task, task-to-event, contact-to-everything).
270 + - **Offline-first with zero cloud dependency** -- SQLite local storage, no account creation, no data on third-party servers. Works fully offline.
271 + - **Zero-knowledge sync** -- when cloud sync ships, all data is end-to-end encrypted client-side (XChaCha20-Poly1305) before leaving the device. The server literally cannot read your data.
272 + - **Pluggable sync providers** -- not locked into one cloud. Choose from GoingsOn Cloud, WebDAV, Dropbox, Google Drive, S3, OneDrive, or a local folder.
273 + - **Source-available** -- unique among all competitors.
274 + - **TaskWarrior-style urgency scoring** -- algorithmic priority considering due date proximity, age, priority level, overdue penalty, started bonus, tag bonuses. More sophisticated than any competitor's priority system.
275 + - **Rhai plugin system** -- user-extensible without forking. Obsidian has plugins but they're JavaScript with no sandboxing.
276 + - **MCP server for Claude integration** -- 40+ structured tools across all domains. No other productivity app exposes this level of programmatic access to an LLM agent. App auto-refreshes when agents modify data.
277 + - **LLM template system** -- dynamic and static LLM templates embedded in text fields, with AI-Fill button for on-demand generation.
278 + - **OAuth2 email for 4 providers** -- Fastmail (JMAP), Google, Microsoft, Yahoo with PKCE flow. Most email clients support fewer OAuth providers.
279 + - **Natural-language quick-add** -- type `Fix bug +urgent project:GoingsOn pri:H due:tomorrow recur:weekly` instead of filling out a form.
280 + - **10 built-in themes** -- Neobrute, Catppuccin (Latte/Frappe/Macchiato/Mocha), Dracula, Nord, Tokyo Night, Flatwhite, Ayu Light.
281 + - **Skeubrute design system** -- distinctive visual identity: paper texture, embossed text, debossed inputs, tactile buttons.
282 + - **Single codebase for desktop + mobile** -- same Rust backend and JS frontend for macOS, Windows, Linux, iOS, and Android via Tauri 2. No Electron, no web framework overhead.
283 + - **Keyboard-first UX** -- vim-style navigation (g+t, j/k, q for quick-add), global shortcuts overlay, full keyboard accessibility.
284 + - **No subscription** -- in a market where annual costs range from $48 to $408.
285 +
286 + ## Key Dynamics
287 +
288 + - Every major competitor is shipping AI features. GoingsOn's MCP server is a developer-facing answer, but end-user AI (summarize, compose, schedule) is the biggest gap.
289 + - Sunsama ($192/yr) is the closest philosophical match -- daily planning, weekly review, calendar+tasks+email integration -- but cloud-only and expensive.
290 + - The offline-first, local-data, source-available combination is a genuine moat for privacy-conscious users.
291 + - Unified workspace eliminates app-switching (vs. using Todoist + Spark + Fantastical separately).
292 + - No subscription required for core features (vs. Fantastical/Sunsama/Spark subscriptions).
293 +
294 + **Biggest competitive gaps to close:**
295 + 1. Kanban/board view for tasks (table stakes for task apps)
296 + 2. Monthly calendar view (everyone expects it)
297 + 3. External calendar sync (already planned, high priority)
298 + 4. Focus timer alongside time blocking (natural fit)
299 + 5. Guided daily planning ritual (complements weekly review)
300 +
301 + **Strongest defenses:**
302 + - Unified workspace eliminates app-switching
303 + - Local-first with E2E encrypted sync
304 + - No subscription for core features
305 + - MCP server for AI agents (unique)
306 + - Plugin system for user extensibility (only Obsidian competes here)
307 +
308 + ## Target Users
309 +
310 + - Independent workers, freelancers, solopreneurs, and solo creators who juggle multiple projects across different domains (software, writing, art, business)
311 + - Power users who want keyboard-driven workflows, natural-language input, and scriptable automation
312 + - Privacy-conscious professionals who want local data ownership with optional end-to-end encrypted sync
313 + - People frustrated with using 4-5 separate apps (task manager + email client + calendar + contacts + notes) who want a single integrated tool
314 +
@@ -0,0 +1,576 @@
1 + # GoingsOn Style Guide
2 +
3 + ## Design Language: Skeubrute
4 +
5 + GoingsOn uses **Skeubrute**, a design system that combines **strong neobrutalism** with **abstract skeuomorphism**.
6 +
7 + ### Core Philosophy
8 +
9 + - **Neobrutalism**: Bold 3px borders, hard-edged offset shadows (4px), high contrast
10 + - **Skeuomorphism**: Paper textures, embossed text effects, tactile button states, realistic depth
11 +
12 + The result is an interface that feels like physical paper and buttons while maintaining a bold, modern aesthetic.
13 +
14 + ---
15 +
16 + ## Color System
17 +
18 + ### Background Colors
19 +
20 + | Variable | Hex | Usage |
21 + |----------|-----|-------|
22 + | `--bg-primary` | `#E8F4F8` | Page background |
23 + | `--bg-secondary` | `#D4EBF2` | Secondary surfaces, hover states |
24 + | `--bg-tertiary` | `#C0E2EC` | Tertiary surfaces |
25 + | `--bg-card` | `#FFFFFF` | Cards, modals, inputs |
26 +
27 + ### Text Colors
28 +
29 + | Variable | Hex | Usage |
30 + |----------|-----|-------|
31 + | `--text-primary` | `#1B365D` | Headings, primary text |
32 + | `--text-secondary` | `#3D5A80` | Body text, descriptions |
33 + | `--text-muted` | `#6B8CAE` | Captions, hints, disabled |
34 +
35 + ### Accent Colors
36 +
37 + | Variable | Hex | Usage |
38 + |----------|-----|-------|
39 + | `--accent-yellow` | `#F7D154` | Primary actions, active states, focus |
40 + | `--accent-green` | `#5CB85C` | Success, active status, tasks |
41 + | `--accent-blue` | `#1B365D` | Borders, info, emails |
42 + | `--accent-purple` | `#7B68EE` | Recurrence, essays, special |
43 + | `--accent-red` | `#DC3545` | Errors, high priority, warnings |
44 + | `--accent-cyan` | `#17A2B8` | Info, side projects, completed |
45 +
46 + ---
47 +
48 + ## Logo
49 +
50 + ### Full Logo
51 +
52 + The GoingsOn wordmark uses **Reglo Bold** with the following specifications:
53 +
54 + - **Font**: Reglo Bold
55 + - **Color**: `--text-primary` (#1B365D) on light backgrounds
56 + - **Alternate**: White on dark backgrounds
57 + - **Letter-spacing**: -0.02em (slightly tightened)
58 +
59 + ### Small Logo (Icon)
60 +
61 + The compact logo displays **"GO"** in Reglo Bold, centered within a neobrutalist container:
62 +
63 + ```
64 + ┌─────────────────┐
65 + │ │
66 + │ GO │
67 + │ │
68 + └─────────────────┘
69 + ```
70 +
71 + **Specifications:**
72 + - **Background**: `--accent-yellow` (#F7D154)
73 + - **Text**: `--text-primary` (#1B365D)
74 + - **Border**: 3px solid `--border-color` (#1B365D)
75 + - **Border Radius**: `--radius-sm` (6px)
76 + - **Shadow**: 2px 2px 0 `--border-color` (neobrutalist offset)
77 +
78 + **Files:**
79 + - `media/logo-go.svg` - Small "GO" icon logo
80 + - `media/logo-goingson.svg` - Full wordmark (future)
81 +
82 + ### Usage Guidelines
83 +
84 + | Context | Logo | Min Size |
85 + |---------|------|----------|
86 + | App icon / Favicon | GO icon | 16x16px |
87 + | Sidebar / Header | GO icon | 32x32px |
88 + | Splash / Marketing | Full wordmark | 120px wide |
89 + | Documentation | Either | Context-dependent |
90 +
91 + ---
92 +
93 + ## Typography
94 +
95 + ### Font Families
96 +
97 + ```css
98 + --font-sans: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
99 + --font-serif: Georgia, 'Times New Roman', serif;
100 + --font-mono: 'SF Mono', 'Consolas', 'Liberation Mono', monospace;
101 + --font-display: 'Reglo', var(--font-serif);
102 + ```
103 +
104 + ### Display Font: Reglo
105 +
106 + The **Reglo** font is used for the logo and prominent H1-style headings. Reglo is an open-source display font with a bold, geometric character that complements the neobrutalist aesthetic.
107 +
108 + - **Source**: [Reglo by Sebastien Sanfilippo](https://github.com/nicokant/reglo) (OFL license)
109 + - **Usage**: Logo wordmark "GoingsOn", hero headings, splash screens
110 + - **Weights**: Bold only (display use)
111 +
112 + ```css
113 + @font-face {
114 + font-family: 'Reglo';
115 + src: url('fonts/Reglo-Bold.woff2') format('woff2');
116 + font-weight: 700;
117 + font-display: swap;
118 + }
119 + ```
120 +
121 + ### Semantic Aliases
122 +
123 + - `--font-display`: Uses `Reglo` for logo and hero headings
124 + - `--font-heading`: Uses `--font-serif` for titles and headings
125 + - `--font-body`: Uses `--font-sans` for body text
126 +
127 + ### Type Scale
128 +
129 + | Element | Size | Weight | Font |
130 + |---------|------|--------|------|
131 + | Page Title | 1.75rem | 700 | Serif |
132 + | Card Title | 1.1rem | 700 | Serif |
133 + | Modal Title | 1.25rem | 700 | Serif |
134 + | Body | 1rem | 400 | Sans |
135 + | Small | 0.875rem | 400 | Sans |
136 + | Caption | 0.75rem | 600 | Sans |
137 +
138 + ---
139 +
140 + ## Spacing
141 +
142 + The spacing system uses a consistent rem-based scale:
143 +
144 + | Name | Value | Usage |
145 + |------|-------|-------|
146 + | xs | 0.25rem | Badge padding, tight gaps |
147 + | sm | 0.5rem | Small gaps, icon spacing |
148 + | md | 0.75rem | Standard padding |
149 + | lg | 1rem | Section padding |
150 + | xl | 1.25rem | Card padding |
151 + | 2xl | 1.5rem | Page margins |
152 +
153 + ---
154 +
155 + ## Border & Shadow System
156 +
157 + ### Border Widths
158 +
159 + | Element | Width |
160 + |---------|-------|
161 + | Cards, Buttons, Modals | 3px (`--border-width`) |
162 + | Inputs, Badges, Tags | 2px |
163 + | Dividers | 2px |
164 +
165 + ### Border Radius
166 +
167 + | Variable | Value | Usage |
168 + |----------|-------|-------|
169 + | `--radius-sm` | 6px | Buttons, badges, inputs |
170 + | `--radius-md` | 12px | Cards, filter bars |
171 + | `--radius-lg` | 16px | Modals |
172 +
173 + ### Shadow System
174 +
175 + ```css
176 + /* Shadow utilities */
177 + .shadow-sm { box-shadow: 2px 2px 0 var(--border-color); }
178 + .shadow-md { box-shadow: 4px 4px 0 var(--border-color); } /* Default */
179 + .shadow-lg { box-shadow: 6px 6px 0 var(--border-color); }
180 + .shadow-xl { box-shadow: 8px 8px 0 var(--border-color); } /* Modals */
181 + .shadow-none { box-shadow: none; }
182 + ```
183 +
184 + ### Offset Shadow Values
185 +
186 + | Element | Shadow Offset |
187 + |---------|---------------|
188 + | Cards | 4px (with stacked paper effect) |
189 + | Buttons | 4px |
190 + | Modals | 8px |
191 + | Small buttons | 2-3px |
192 + | Inputs | Inset deboss |
193 +
194 + ---
195 +
196 + ## Skeuomorphic Effects
197 +
198 + ### Paper Texture
199 +
200 + Cards have a subtle SVG noise pattern for a paper-like feel:
201 +
202 + ```css
203 + .card {
204 + background-image: var(--texture-paper);
205 + }
206 + ```
207 +
208 + ### Embossed Text
209 +
210 + Headings use subtle text shadows to create a pressed-in effect:
211 +
212 + ```css
213 + .card-title, .modal-title, .page-title {
214 + text-shadow: var(--emboss-light), var(--emboss-dark);
215 + }
216 + ```
217 +
218 + Where:
219 + - `--emboss-light`: `1px 1px 0 rgba(255, 255, 255, 0.5)`
220 + - `--emboss-dark`: `-1px -1px 0 rgba(0, 0, 0, 0.08)`
221 +
222 + ### Debossed Inputs
223 +
224 + Form inputs have an inset shadow for a carved-in feel:
225 +
226 + ```css
227 + .form-input {
228 + box-shadow: var(--deboss);
229 + }
230 + /* --deboss: inset 1px 1px 2px rgba(0,0,0,0.08), inset -1px -1px 0 rgba(255,255,255,0.5) */
231 + ```
232 +
233 + ### Tactile Buttons
234 +
235 + Buttons have a gradient overlay for a 3D, pressable feel:
236 +
237 + ```css
238 + .btn {
239 + background-image: var(--btn-gradient);
240 + }
241 + .btn:active {
242 + background-image: var(--btn-gradient-pressed);
243 + }
244 + ```
245 +
246 + ---
247 +
248 + ## Components
249 +
250 + ### Buttons
251 +
252 + ```html
253 + <!-- Primary button (yellow background) -->
254 + <button class="btn btn-primary">Action</button>
255 +
256 + <!-- Secondary button (light background) -->
257 + <button class="btn btn-secondary">Cancel</button>
258 +
259 + <!-- Small button -->
260 + <button class="btn btn-sm">Small</button>
261 + ```
262 +
263 + **States:**
264 + - **Default**: 4px offset shadow
265 + - **Hover**: Lifts up (-2px, -2px), shadow increases
266 + - **Active/Pressed**: Pushes down (2px, 2px), shadow disappears
267 +
268 + ### Cards
269 +
270 + ```html
271 + <div class="card">
272 + <div class="card-header">
273 + <h3 class="card-title">Card Title</h3>
274 + </div>
275 + <p class="card-description">Description text</p>
276 + <div class="card-meta">
277 + <span class="tag type-job">Job</span>
278 + <span class="tag status-active">Active</span>
279 + </div>
280 + </div>
281 + ```
282 +
283 + Cards have:
284 + - Paper texture background
285 + - Stacked paper shadow effect (two-layer shadow)
286 + - Lift on hover
287 +
288 + ### Badges & Tags
289 +
290 + **Using data attributes (preferred):**
291 +
292 + ```html
293 + <span class="badge" data-color="green">Success</span>
294 + <span class="badge" data-color="yellow">Warning</span>
295 + <span class="badge" data-color="red">Error</span>
296 + <span class="badge" data-color="cyan">Info</span>
297 + <span class="badge" data-color="purple">Special</span>
298 + <span class="badge" data-color="muted">Default</span>
299 + ```
300 +
301 + **Legacy classes:**
302 +
303 + ```html
304 + <span class="tag type-job">Job</span>
305 + <span class="tag type-sideproject">Side Project</span>
306 + <span class="tag status-active">Active</span>
307 + <span class="tag status-completed">Completed</span>
308 + ```
309 +
310 + ### Form Inputs
311 +
312 + ```html
313 + <div class="form-group">
314 + <label class="form-label">Label</label>
315 + <input type="text" class="form-input" placeholder="Enter text...">
316 + </div>
317 +
318 + <div class="form-group">
319 + <label class="form-label">Select</label>
320 + <select class="form-select">
321 + <option>Option 1</option>
322 + </select>
323 + </div>
324 +
325 + <div class="form-group">
326 + <label class="form-label">Textarea</label>
327 + <textarea class="form-textarea"></textarea>
328 + </div>
329 + ```
330 +
331 + **Focus state**: Yellow ring (3px) around the input
332 +
333 + ### Modals
334 +
335 + ```html
336 + <div class="modal-overlay">
337 + <div class="modal-container">
338 + <div class="modal-header">
339 + <h2 class="modal-title">Modal Title</h2>
340 + <button class="modal-close">&times;</button>
341 + </div>
342 + <div class="modal-content">
343 + <!-- Content here -->
344 + </div>
345 + </div>
346 + </div>
347 + ```
348 +
349 + Modals have:
350 + - 8px offset shadow
351 + - 16px border radius
352 + - Semi-transparent overlay
353 +
354 + ### Tables
355 +
356 + ```html
357 + <table class="task-table">
358 + <thead>
359 + <tr>
360 + <th>Column</th>
361 + </tr>
362 + </thead>
363 + <tbody>
364 + <tr>
365 + <td>Data</td>
366 + </tr>
367 + </tbody>
368 + </table>
369 + ```
370 +
371 + Features:
372 + - Uppercase, letter-spaced headers
373 + - Hover state on rows
374 + - Selected state (yellow background)
375 +
376 + ### Empty & Error States
377 +
378 + ```html
379 + <div class="empty-state">
380 + <div class="empty-state-icon">icon</div>
381 + <p class="empty-state-text">No items found</p>
382 + </div>
383 +
384 + <div class="error-state">
385 + Error message here
386 + </div>
387 + ```
388 +
389 + ---
390 +
391 + ## Animation Standards
392 +
393 + ### Timing
394 +
395 + | Type | Duration | Easing |
396 + |------|----------|--------|
397 + | Hover effects | 0.1s - 0.15s | ease |
398 + | Transform (lift/press) | 0.1s | ease |
399 + | Focus rings | instant | - |
400 +
401 + ### Hover Lift Effect
402 +
403 + ```css
404 + .hover-lift {
405 + transition: transform 0.15s ease, box-shadow 0.15s ease;
406 + }
407 + .hover-lift:hover {
408 + transform: translate(-2px, -2px);
409 + }
410 + .hover-lift:active {
411 + transform: translate(2px, 2px);
412 + }
413 + ```
414 +
415 + ---
416 +
417 + ## Accessibility
418 +
419 + ### Focus States
420 +
421 + All interactive elements have visible focus indicators:
422 +
423 + ```css
424 + .btn:focus-visible,
425 + .form-input:focus-visible {
426 + outline: 3px solid var(--accent-yellow);
427 + outline-offset: 2px;
428 + }
429 + ```
430 +
431 + ### Screen Reader Support
432 +
433 + Use `.sr-only` for visually hidden but accessible text:
434 +
435 + ```html
436 + <span class="sr-only">Screen reader text</span>
437 + ```
438 +
439 + ### Color Contrast
440 +
441 + All text colors meet WCAG AA standards against their backgrounds:
442 + - Primary text on card: 8.5:1
443 + - Secondary text on card: 5.2:1
444 + - Muted text on card: 3.8:1
445 +
446 + ---
447 +
448 + ## File Organization
449 +
450 + ```
451 + src-tauri/frontend/
452 + ├── css/
453 + │ └── styles.css # All styles (design system + components)
454 + ├── fonts/
455 + │ └── Reglo-Bold.woff2 # Display font
456 + ├── js/
457 + │ ├── goingson.js # Namespace root (window.GoingsOn)
458 + │ ├── api.js # Tauri IPC abstraction
459 + │ ├── state.js # Centralized state + pub/sub
460 + │ ├── utils.js # HTML escaping, validation, debounce
461 + │ ├── components.js # Modal, toast, form modal, confirm dialog
462 + │ ├── navigation.js # View switching, sidebar
463 + │ ├── tasks.js # Task list, CRUD, rendering
464 + │ ├── projects.js # Project list, detail view
465 + │ ├── events.js # Event list, CRUD
466 + │ ├── emails.js # Email list, threading
467 + │ ├── settings.js # Settings, LLM config, export
468 + │ └── app.js # App initialization, menu listeners
469 + └── index.html # Entry point (no inline styles)
470 + ```
471 +
472 + See `ARCHITECTURE.md` (in this folder) for the full JS file listing and namespace organization.
473 +
474 + ---
475 +
476 + ## CSS Naming Convention
477 +
478 + GoingsOn uses a simplified BEM-adjacent pattern with kebab-case.
479 +
480 + ### Pattern: `.block-element`
481 +
482 + ```
483 + .component → Block (card, modal, btn, form)
484 + .component-part → Element within block (card-header, modal-title)
485 + .component-modifier → Variant (btn-primary, btn-sm)
486 + ```
487 +
488 + ### Examples
489 +
490 + ```css
491 + /* Block */
492 + .card { }
493 + .modal { }
494 + .btn { }
495 +
496 + /* Elements (single hyphen) */
497 + .card-header { }
498 + .card-title { }
499 + .card-description { }
500 + .modal-overlay { }
Lines truncated
@@ -0,0 +1,118 @@
1 + # GoingsOn - Roadmap
2 +
3 + Pending features and improvements. Completed work archived in `docs/archive/go_todo_done.md`.
4 +
5 + **Scope:** Sections tagged `(pre-beta)` ship before initial beta. Untagged sections are post-beta. Ready for extensive human testing.
6 +
7 + ---
8 +
9 + ## Desktop Distribution
10 +
11 + ### Mobile Port (Tauri 2)
12 + CSS-first responsive design with touch gesture module. See **[todo_mobile.md](./todo_mobile.md)** for remaining work.
13 +
14 + **Remaining (pre-beta):**
15 + - [ ] `cargo tauri android init`
16 + - [ ] Test all CRUD operations on mobile WebView
17 + - [ ] Physical device testing and polish
18 +
19 + ### Windows Build (pre-beta)
20 + - [ ] `cargo tauri build` on Windows — verify `.msi` installer
21 + - [ ] Test on Windows (VM or physical)
22 + - [ ] Code-sign with Authenticode certificate
23 +
24 + ### Linux Build
25 + - [ ] AppImage (x86_64 + aarch64), .deb, .rpm. Deps: WebKit2GTK 4.1, OpenSSL, libayatana-appindicator.
26 +
27 + ### Package Managers (post-beta)
28 + - [ ] Homebrew Cask (macOS), Flatpak (Linux), winget (Windows)
29 + - [ ] MCP server standalone binary (~7MB) — separate distribution for CLI/agent users
30 +
31 + ---
32 +
33 + ### Calendar Views
34 + - [ ] Restructure navigation: domain tabs vs temporal views (day/week/month)
35 + - [ ] Month calendar view (grid with event + task dots)
36 + - [ ] Week view (multi-day timeline)
37 +
38 + ### Time Tracking
39 + - [ ] Optional `estimated_minutes` field on tasks
40 + - [ ] Start/stop timer, actual vs estimated comparison
41 + - [ ] Focus timer mode (Pomodoro-style linked to active task)
42 + - [ ] Time tracking summary: per-project and per-day totals
43 +
44 + ### Cloud Sync — Remaining
45 + #### Pre-beta
46 + - [ ] Test full sync flow against live MNW server
47 +
48 + #### Post-beta
49 + - [ ] Recovery key generation (printable paper backup for encryption password)
50 +
51 + #### Deferred
52 + - [ ] Field-level merge / conflict resolution UI
53 + - [ ] Sync provider plugins (filesystem, WebDAV, S3-compatible)
54 + - [ ] Sync history/log viewer
55 + - [ ] Send Later (cloud-dependent)
56 + - [ ] Activity log
57 +
58 + ---
59 +
60 + ### File Attachments
61 + Depends on Cloud Sync.
62 + - [ ] Attachment storage, attach to tasks/projects, view email attachments, download, link to local files, thumbnails
63 +
64 + ### Passkey Authentication (WebAuthn/FIDO2)
65 + - [ ] Phase 1: Local biometric unlock (Touch ID, Windows Hello)
66 + - [ ] Phase 2: Hardware security key support (YubiKey, SoloKey)
67 + - [ ] Phase 3: Cloud passkey authentication
68 + - [ ] Phase 4: E2EE key protection (passkey PRF extension)
69 +
70 + ### Agent Integration (MCP Server) — Remaining
71 + - [ ] Phase 3: In-app agent tab (chat UI, message history, tool calling, streaming)
72 + - [ ] Phase 4: Conversation persistence, suggested actions, keyboard shortcuts
73 +
74 + ### Plugin System (Rhai) — Remaining
75 + - [ ] Phase 3: Export adapters, custom commands, lifecycle hooks
76 + - [ ] Phase 4: Hot-reload, AST cache, install from URL, update checking
77 + - [ ] Starter plugins: import (TaskWarrior, Todoist, Things 3, Apple Reminders, Notion, Trello, Google Tasks), export (CSV, JSON, Markdown, ICS, Obsidian)
78 + - [ ] Contact plugins: import (vCard, Apple, Google, Microsoft, LinkedIn), sync (CardDAV, Google, Microsoft Graph)
79 + - [ ] Calendar sync: Google, Apple/iCloud CalDAV, generic CalDAV, .ics import
80 + - [ ] External tools: Raycast, Alfred, iOS Shortcuts, Zapier/Make webhooks
81 +
82 + ---
83 +
84 + ## OAuth Provider Registration
85 +
86 + | Provider | Registered | Client ID Set | Tested |
87 + |-----------|:----------:|:-------------:|:------:|
88 + | Fastmail | [~] (email sent) | [ ] | [ ] |
89 + | Google | [x] | [x] | [ ] |
90 + | Microsoft | [x] | [x] | [ ] |
91 +
92 + ## Shared Code Extraction (Cross-Project)
93 + - [ ] Updater UI: extract nearly-identical updater.js from GO/BB into shared module
94 + - [ ] Theme loading: deduplicate TOML theme parser across GO/BB/AF
95 + - [ ] Rhai host functions: deduplicate plugin runtime setup across GO/BB/AF
96 + - [ ] Saved queries: unify GO saved views, BB query feeds, AF smart folders into shared pattern
97 + - [ ] FTS5 query building: extract shared SQLite full-text search utilities
98 +
99 + ## Deferred
100 + - [ ] Co-working feature: E2E encrypted project sharing via UUID-based links (key material in URL fragment, never sent to server). XChaCha20-Poly1305 symmetric per project, X25519 key exchange, Argon2 key derivation. Relay server MVP, P2P later. CRDTs for conflict resolution (LWW-Register for fields, OR-Set for tags, RGA for ordered lists). Permissions: viewer / collaborator / admin / owner. Shareable units: project, saved view, calendar overlay (busy/free only), individual task. 7 implementation phases.
101 + - [ ] Portability: publish synckit-client as a crate or use git submodule
102 + - [ ] Apple Watch app
103 + - [ ] Home screen widgets (iOS/Android)
104 +
105 + ---
106 +
107 + ## Architecture
108 + ```
109 + crates/core/ Domain types, urgency calc, parser, repository traits
110 + crates/db-sqlite/ SQLite repository implementations
111 + crates/plugin-runtime/ Rhai plugin system
112 + plugins/ Bundled reference plugins
113 + src-tauri/ Desktop app (Tauri 2 + vanilla JS)
114 + migrations/sqlite/ SQLite migrations
115 + ```
116 +
117 + - **Domain purchased:** goingson.app (Feb 2026)
118 + - docs/architecture.md documents crate structure and data flow
@@ -0,0 +1,205 @@
1 + # GoingsOn - Mobile Port
2 +
3 + Tauri 2 iOS/Android port. CSS-first responsive design with touch gesture module.
4 +
5 + **What stays the same:**
6 + - `crates/core/` — domain logic, unchanged
7 + - `crates/db-sqlite/` — SQLite repository, unchanged
8 + - `src-tauri/src/commands/` — Tauri commands, unchanged
9 + - `src-tauri/frontend/js/` — all JS modules (minor mobile branches)
10 + - `api.js` with `invoke()` — same IPC mechanism
11 +
12 + **What changed:** CSS responsiveness, touch interaction module, mobile navigation, Tauri mobile configuration.
13 +
14 + ---
15 +
16 + ## Completed Work
17 +
18 + ### Phase 1: CSS Foundation
19 + - [x] `@media (max-width: 768px)` breakpoint in `styles.css`
20 + - [x] `@media (hover: none)` disables sticky hover effects
21 + - [x] `viewport-fit=cover` meta tag
22 + - [x] Safe area insets on fixed elements (`env(safe-area-inset-*)`)
23 + - [x] Tab navigation hidden on mobile
24 + - [x] Page titles hidden on mobile (shown in header instead)
25 + - [x] "Project Management" subtitle hidden, current view title in header
26 + - [x] Contacts & Settings buttons in upper-right header (stacked vertically)
27 + - [x] Task table → card layout with priority-colored left borders
28 + - [x] Event table → list reflow
29 + - [x] Modals → bottom sheets (anchored to bottom, rounded top corners, drag handle)
30 + - [x] Toasts repositioned for mobile
31 + - [x] Filter bar collapses on mobile
32 + - [x] Mobile sort bar for tasks
33 + - [x] Day plan sidebar toggle button
34 +
35 + ### Phase 2: Touch Module (`js/touch.js`)
36 + - [x] `isTouchDevice` detection
37 + - [x] `addLongPress(element, callback, duration)`
38 + - [x] `addSwipeActions(element, config)`
39 + - [x] `addPullToRefresh(container, callback)`
40 + - [x] `addSwipeNavigation(container, handlers)`
41 + - [x] `addDragToDismiss(element, onDismiss)`
42 + - [x] All functions return cleanup functions, all are no-ops on non-touch devices
43 +
44 + ### Phase 3: Navigation + Bottom Sheets
45 + - [x] Floating nav dot (70px Skeubrute button, bottom-right)
46 + - [x] Radial petal dial (6 views: Projects, Tasks, Emails, Events, Daily, Weekly)
47 + - [x] Rectangular petal spokes with auto-computed radius (no overlap)
48 + - [x] 90° arc based on which corner the dot is nearest
49 + - [x] Petals rotated along spoke, flipped for readability
50 + - [x] Reverse z-order for natural fan overlap
51 + - [x] Center "+" button creates new item for current view
52 + - [x] Click handler (mouse) + touch handler (tap vs drag)
53 + - [x] Double-fire prevention (touch + synthesized click)
54 + - [x] Action bottom sheets replace context menus on touch
55 + - [x] `showContextMenuSmart()` delegates to action sheet on touch, regular menu on desktop
56 + - [x] Modal swipe-to-dismiss wiring
57 +
58 + ### Phase 4: View Adaptations
59 + - [x] Tasks: mobile sort dropdown, filter bottom sheet toggle
60 + - [x] Events: date group headers in mobile render
61 + - [x] Events: status indicator below nav dot (dial closed) / on petal badge (dial open)
62 + - [x] Events: indicator logic — empty if no events today, green if none soon, yellow if imminent, red if now
63 + - [x] Events tab pushed to far right on desktop (`margin-left: auto`)
64 + - [x] Day plan: `onSlotTap` handler (tap-to-create with 30min default on touch)
65 + - [x] Day plan: swipe left/right navigates days
66 + - [x] Day plan: collapsible unscheduled tasks sidebar
67 + - [x] Emails: in-app compose modal on mobile (no separate window)
68 + - [x] Keyboard shortcuts disabled on touch devices
69 +
70 + ### Phase 5: Tauri Mobile Build Config
71 + - [x] `Cargo.toml`: desktop-only deps gated with `cfg(not(any(target_os = "ios", target_os = "android")))`
72 + - `tauri-plugin-shell`, `tauri-plugin-notification`, `tauri-plugin-window-state`, `notify`, `notify-debouncer-mini`
73 + - [x] `Cargo.toml`: `crate-type = ["staticlib", "cdylib", "lib"]` for iOS static library
74 + - [x] `lib.rs`: `db_watcher` and `notifications` modules gated for desktop only
75 + - [x] `lib.rs`: `build_mobile_app()` function + `#[cfg(mobile)] #[tauri::mobile_entry_point]`
76 + - [x] `main.rs`: desktop-only plugin init, tray, background services gated with `cfg`
77 + - [x] `commands/window.rs`: `open_compose_window` and `set_window_title` gated for desktop only
78 + - [x] `tauri.conf.json`: identifier `com.goingson.app`, minWidth 320
79 + - [x] Capabilities split: `default.json` (cross-platform) + `desktop.json` (shell, notifications)
80 + - [x] `cargo tauri ios init` → generates `gen/apple/` Xcode project
81 + - [x] Builds and runs on iOS simulator (iPhone 17 Pro, iOS 26.2)
82 + - [x] Safe area inset padding on header for iOS dynamic island
83 +
84 + ---
85 +
86 + ## Remaining Work
87 +
88 + ### Build & Test
89 + - [x] Run `cargo tauri ios init` (creates `gen/apple/`)
90 + - [ ] Run `cargo tauri android init` (creates `gen/android/`)
91 + - [x] Add Rust cross-compilation targets (`rustup target add aarch64-apple-ios-sim`)
92 + - [x] Test on iOS simulator (`cargo tauri ios dev "iPhone 17 Pro"`)
93 + - [ ] Test on Android emulator (`cargo tauri android dev`)
94 + - [x] Verify SQLite path resolution via `app_data_dir()`
95 + - [ ] All CRUD operations verified on mobile WebView
96 +
97 + ### Interaction Wiring
98 + - [x] Wire swipe actions to task rows (swipe right: complete, swipe left: snooze)
99 + - [x] Wire swipe actions to email items (swipe right: archive, swipe left: delete)
100 + - [x] Wire swipe actions to event rows (swipe left: delete)
101 + - [x] Wire pull-to-refresh to list views (tasks, emails, events)
102 + - [x] Long-press selection mode on list items (tasks, emails — toggles bulk selection)
103 + - [x] Nav dot drag-to-reposition (touch drag with edge snapping — tested, working)
104 +
105 + ### Polish
106 + - [ ] Physical device testing (iOS + Android)
107 + - [ ] Safe area insets on various device models (notched, non-notched)
108 + - [ ] Virtual scroller performance on mobile
109 + - [ ] VoiceOver / TalkBack accessibility
110 + - [ ] Keyboard doesn't obscure inputs in modals
111 + - [ ] Background/foreground transitions work correctly
112 +
113 + ### Platform Features (Future)
114 + - [ ] Push notifications via Tauri plugin
115 + - [ ] Haptic feedback for actions
116 + - [ ] Share extension (receive shared text as task)
117 + - [ ] Widgets (iOS 14+, Android)
118 + - [ ] Biometric unlock (Face ID, fingerprint)
119 +
120 + ---
121 +
122 + ## Key Files
123 +
124 + | File | Role |
125 + |------|------|
126 + | `src-tauri/frontend/css/styles.css` | All responsive CSS (~400 lines of mobile rules) |
127 + | `src-tauri/frontend/js/touch.js` | Gesture utilities (~300 lines) |
128 + | `src-tauri/frontend/js/navigation.js` | Nav dot + radial dial |
129 + | `src-tauri/frontend/js/components.js` | Action sheets, modal swipe-dismiss |
130 + | `src-tauri/frontend/js/day-planning.js` | Tap-to-create, swipe day nav |
131 + | `src-tauri/frontend/js/events.js` | Mobile status indicator, date groups |
132 + | `src-tauri/frontend/js/emails.js` | In-app compose modal |
133 + | `src-tauri/frontend/js/mobile.js` | Swipe, pull-to-refresh, long-press wiring |
134 + | `src-tauri/frontend/js/keyboard.js` | Touch device gate |
135 + | `src-tauri/frontend/index.html` | Nav dot/dial HTML, mobile elements |
136 + | `src-tauri/Cargo.toml` | Desktop-only dep gating |
137 + | `src-tauri/src/main.rs` | Desktop-only plugin/service gating |
138 + | `src-tauri/src/lib.rs` | Desktop-only module gating |
139 +
140 + ---
141 +
142 + ## Running on Mobile
143 +
144 + ```bash
145 + # iOS
146 + cargo tauri ios dev # simulator
147 + cargo tauri ios dev --device "iPhone 15 Pro" # specific simulator
148 + cargo tauri ios dev --device # physical device (needs provisioning)
149 +
150 + # Android
151 + cargo tauri android dev # emulator
152 + cargo tauri android dev --device "Pixel_7" # specific emulator
153 + cargo tauri android dev --device # physical device (USB debugging)
154 + ```
155 +
156 + **WebView debugging:**
157 + - iOS: Safari → Develop → Simulator → JSContext
158 + - Android: Chrome → `chrome://inspect` → Select WebView
159 +
160 + ---
161 +
162 + ## Known Issues
163 +
164 + **iOS Simulator deploy race condition** — `cargo tauri ios dev` sometimes fails with "Unable to lookup in current state: Shutdown" even though the simulator appears booted. Workaround: boot the simulator manually first (`open -a Simulator && sleep 5`) before running `cargo tauri ios dev`. If it still fails, install/launch manually:
165 + ```bash
166 + xcrun simctl install booted /path/to/GoingsOn.app
167 + xcrun simctl launch booted com.goingson.app
168 + ```
169 +
170 + **SQLite on Android** — If SQLite fails to load, bundle it:
171 + ```toml
172 + [target.'cfg(target_os = "android")'.dependencies]
173 + rusqlite = { version = "0.31", features = ["bundled"] }
174 + ```
175 +
176 + **Tauri macOS WebView** — Uses WKWebView with Safari Web Inspector (not Chrome DevTools). No responsive design mode in inspector; resize the window to test mobile breakpoint.
177 +
178 + ---
179 +
180 + ## Release
181 +
182 + ### iOS (TestFlight)
183 + ```bash
184 + cargo tauri ios build --release
185 + # Output: src-tauri/gen/apple/build/ → Open in Xcode to archive and upload
186 + ```
187 + - [x] Apple Developer account ($99/year) — approved
188 + - [ ] Provisioning profiles configured (distribution profile for `com.goingson.app`)
189 + - [ ] App Store Connect: create app record
190 + - [ ] `cargo tauri ios build --release` — archive in Xcode
191 + - [ ] Upload to TestFlight via Xcode or `xcrun altool`
192 + - [ ] Add beta testers
193 + - [ ] Physical device testing before sending TestFlight invites
194 +
195 + ### Android
196 + ```bash
197 + cargo tauri android build --release --aab
198 + # Output: src-tauri/gen/android/app/build/outputs/
199 + ```
200 + - [ ] Google Play Developer account ($25 one-time)
201 + - [ ] `cargo tauri android init`
202 + - [ ] Signing key generated (Android keystore)
203 + - [ ] Play Console listing (title, description, screenshots)
204 + - [ ] Test on emulator + physical device
205 + - [ ] Play Store submission
@@ -19,7 +19,7 @@ tauri-build = { workspace = true }
19 19 goingson-core = { workspace = true }
20 20 goingson-db-sqlite = { workspace = true }
21 21 goingson-plugin-runtime = { workspace = true }
22 - synckit-client = { path = "../../synckit-client" }
22 + synckit-client = { path = "../../../Shared/synckit-client" }
23 23
24 24 # Tauri
25 25 tauri = { workspace = true, features = ["image-png"] }
@@ -38,7 +38,7 @@
38 38 "icons/icon.ico"
39 39 ],
40 40 "resources": [
41 - "../../../themes/*.toml"
41 + "../../../Shared/themes/*.toml"
42 42 ],
43 43 "iOS": {
44 44 "developmentTeam": "93C54W92UP"