[{"data":1,"prerenderedAt":526},["ShallowReactive",2],{"blog-redesigned-mobile-app":3,"blog-related-redesigned-mobile-app":248},{"id":4,"title":5,"author":6,"body":7,"category":233,"date":234,"description":235,"draft":236,"extension":237,"featured":238,"image":239,"imageAlt":239,"meta":240,"navigation":238,"ogImage":239,"path":241,"seo":242,"stem":243,"tags":244,"updated":239,"__hash__":247},"blog\u002Fblog\u002Fredesigned-mobile-app.md","We rebuilt the 1410SMS mobile app, screen by screen","team",{"type":8,"value":9,"toc":218},"minimark",[10,14,17,20,25,28,31,34,41,47,53,57,62,65,68,79,83,86,89,92,96,99,140,147,150,154,157,160,164,167,170,173,177,180,185,188,191,195,198,201,204],[11,12,13],"p",{},"The first version of the 1410SMS mobile app did the job. Staff could mark a register on it, parents\ncould check a balance on it, and it worked offline on a bad connection, which in a lot of Nigerian\nschools is the whole ballgame.",[11,15,16],{},"It also, if we are honest, looked like a filing cabinet.",[11,18,19],{},"Version 1.1.0 is the result of going back through every screen in the app and asking a question we\nshould have asked earlier: does this feel like something built for a phone, or like a website that\nhas been squeezed onto one?",[21,22,24],"h2",{"id":23},"the-problem-with-it-works","The problem with \"it works\"",[11,26,27],{},"An app that works is not the same as an app people reach for.",[11,29,30],{},"A bursar with a laptop open will use the laptop. A class teacher standing in a corridor will not open\na laptop, so if the app is awkward the register gets marked later, from memory, which is how\nattendance data quietly stops being true. The gap between \"the feature exists on mobile\" and \"people\nactually use it on mobile\" is almost entirely a design gap.",[11,32,33],{},"Three things were pushing people back to the browser:",[11,35,36,40],{},[37,38,39],"strong",{},"Every screen looked slightly different from every other screen."," Some had a card with a shadow,\nsome had a card with a border, some had neither. Status colours were whatever green or red that\nscreen's author had picked. Nothing was wrong exactly, but nothing agreed either, and the cumulative\neffect is that an app stops feeling like one product.",[11,42,43,46],{},[37,44,45],{},"Half the finance features were read-only."," You could look at an invoice on the phone but not\nrecord the payment against it, so anyone doing the actual work was going back to a desk anyway.",[11,48,49,52],{},[37,50,51],{},"Some screens were built like web pages."," The clearest case was taking a test: one long scroll with\nevery question on it, which is exactly how you would build it for a browser and exactly the wrong\nshape for a thumb.",[21,54,56],{"id":55},"what-we-changed","What we changed",[58,59,61],"h3",{"id":60},"one-header-one-card-one-set-of-status-colours","One header, one card, one set of status colours",[11,63,64],{},"The app now has a shared screen shell. Your school's logo and name sit above the screen title in the\nsame position on every screen, over a soft backdrop, with summary panels rendered as flat cards with\na hairline border rather than floating on a shadow.",[11,66,67],{},"That sounds like a small thing. It is the difference between an interface you read and an interface\nyou decode. When a paid badge is the same green on the invoice list, the invoice detail, the pupil's\nrecord and the dashboard, you stop reading the word and start recognising the colour, which is faster\nand is what a native app is supposed to feel like.",[69,70,76],"screenshot",{":phone":71,"alt":72,"height":73,"src":74,"width":75},"true","The 1410SMS Android app staff dashboard: a green header greeting Adaeze Okonkwo above the school name, term and session, then ₦1.20M collected in 2026\u002F2027 of ₦1.23M invoiced at 98%, a session and term filter, student, teacher, class and parent counts, and a Needs chasing card naming one family 59 days overdue for ₦25,000",1600,"\u002Fdocs\u002Fmobile-app\u002Fdashboard.png",720,[11,77,78],{},"The staff dashboard. The same widgets, the same period filter and the same permissions as the web.",[58,80,82],{"id":81},"tablets-and-very-large-text","Tablets, and very large text",[11,84,85],{},"Two cases we had been quietly ignoring.",[11,87,88],{},"A tablet was getting the phone layout stretched wide, so a four-across row of figures sat as two\ncolumns with a lot of empty space. Stat grids now go to four columns above 600dp with wider margins.",[11,90,91],{},"The other was more embarrassing. With the system font size set to its largest accessibility value,\na single word could become wider than the fixed-width column it sat in, and the layout engine\nresponded by wrapping one character per line. Text scaling is now capped at a point where every\nlayout still holds together, which is not a perfect answer but is a great deal better than a column\nof individual letters.",[58,93,95],{"id":94},"finance-you-can-actually-run-from-a-phone","Finance you can actually run from a phone",[11,97,98],{},"This was the biggest functional gap, so it got the most work. The app now has:",[100,101,102,110,116,122,128,134],"ul",{},[103,104,105,106,109],"li",{},"A ",[37,107,108],{},"Payments workspace"," with the verification queue, so a payment can be reviewed, verified,\nrejected with a reason, or voided if it was recorded in error, without opening a browser.",[103,111,112,115],{},[37,113,114],{},"Invoice search and sort",", because scrolling to find one invoice is fine with thirty and\nimpossible with three hundred.",[103,117,118,121],{},[37,119,120],{},"Fee structures",", so the fee types an invoice is built from can be created and edited on the\nphone rather than only read.",[103,123,124,127],{},[37,125,126],{},"Bulk reminders",": long-press to start selecting, tap to add, one action to send every selected\nparent their own reminder.",[103,129,130,133],{},[37,131,132],{},"Analytics and outstanding",", including a collection-rate ring, a twelve-month trend, and the\ndebtors list.",[103,135,136,139],{},[37,137,138],{},"Fee discounts",", both the catalogue and the awards against individual pupils.",[69,141,144],{":phone":71,"alt":142,"height":73,"src":143,"width":75},"The 1410SMS Android app Fees screen: term and session filter chips, an outstanding card showing ₦25,000 in NGN beside a 98% collected ring with one part-paid and six paid, above a searchable list of invoices each naming the pupil, the fee items and what is still owed","\u002Fdocs\u002Fmobile-app\u002Ffees.png",[11,145,146],{},"Outstanding balances get one card per currency, because balances in different currencies are never added together.",[11,148,149],{},"Every one of those is gated on the same permissions as the web, so what a role can do does not change\ndepending on which device they are holding.",[58,151,153],{"id":152},"taking-a-test-redesigned","Taking a test, redesigned",[11,155,156],{},"Candidates now see one question at a time, with a numbered strip above showing which questions are\nanswered, which one they are on, and letting them jump straight to any of them. Submit is available\nfrom any question rather than only the last, and asks for confirmation if anything is unanswered.",[11,158,159],{},"While we were in there we fixed something worse than a layout problem. The countdown had been driven\nby the test's duration rather than by the deadline the server issued, which meant reloading the page\nbought a fresh full timer. It now runs off the server's deadline, so the clock a candidate sees and\nthe cut-off the server enforces are the same clock.",[58,161,163],{"id":162},"the-screens-nobody-wants-to-see","The screens nobody wants to see",[11,165,166],{},"Two failure states were badly served.",[11,168,169],{},"A school whose subscription had lapsed got empty screens and a Try again button that could never\nsucceed, because every request was being refused. The app now says so plainly, explains that renewal\nhappens in the web portal, and restores itself the moment payment goes through.",[11,171,172],{},"And figures used to go stale. Recording a payment updated the invoice but left the dashboard on its\nold number until you reopened the screen, which is exactly the kind of thing that makes someone\ndistrust a total. Writes now invalidate the figures they affect, so what you see after an action is\nwhat actually happened.",[21,174,176],{"id":175},"the-rule-we-used","The rule we used",[11,178,179],{},"Partway through, we stopped arguing about individual screens and settled on a test.",[11,181,182],{},[37,183,184],{},"A screen is finished when nothing about it tells you it came from a web page.",[11,186,187],{},"Not \"does it look nice\". Not \"does it match the mockup\". Whether anything on it, a layout, a\ncontrol, an interaction, a scroll length, would only make sense on a desktop. A form with fourteen\nfields in a single column fails that test. A confirmation you can only reach by scrolling to the\nbottom of a long list fails it. A table with five columns squashed to phone width fails it badly.",[11,189,190],{},"It is a useful rule because it is answerable. Two people can disagree about whether a card should\nhave a shadow for a long time. They can settle \"would you build it this way if the web version did\nnot exist\" in about a minute.",[21,192,194],{"id":193},"what-is-next","What is next",[11,196,197],{},"The redesign is not a finished project, it is a standard we now hold new screens to. The next passes\nare the academic side, which has had less attention than finance, and offline behaviour, where the\napp is capable but does not always explain itself well enough.",[11,199,200],{},"If you use the app, update to 1.1.0 and tell us where it still feels like a website. That feedback is\nmore useful to us than almost anything else.",[202,203],"app-download",{},[11,205,206,207,212,213,217],{},"The full list of changes is in the ",[208,209,211],"a",{"href":210},"\u002Freleases\u002Fmobile-1-1-0","release notes",", and\n",[208,214,216],{"href":215},"\u002Fdocs\u002Fmobile-app","Mobile App"," in the documentation covers signing in, push notifications and offline\nsupport.",{"title":219,"searchDepth":220,"depth":220,"links":221},"",3,[222,224,231,232],{"id":23,"depth":223,"text":24},2,{"id":55,"depth":223,"text":56,"children":225},[226,227,228,229,230],{"id":60,"depth":220,"text":61},{"id":81,"depth":220,"text":82},{"id":94,"depth":220,"text":95},{"id":152,"depth":220,"text":153},{"id":162,"depth":220,"text":163},{"id":175,"depth":223,"text":176},{"id":193,"depth":223,"text":194},"Guides","2026-07-29","Why the app needed more than a coat of paint, what changed in the redesign, and the rule we used to decide when a screen was finished.",false,"md",true,null,{},"\u002Fblog\u002Fredesigned-mobile-app",{"title":5,"description":235},"blog\u002Fredesigned-mobile-app",[245,246],"mobile","product","XADBTTzv-xtcIxDq5LgQJNuCSzGYpW541cZPRYfJBRI",[249,412],{"id":250,"title":251,"author":6,"body":252,"category":401,"date":402,"description":403,"draft":236,"extension":237,"featured":236,"image":239,"imageAlt":239,"meta":404,"navigation":238,"ogImage":239,"path":405,"seo":406,"stem":407,"tags":408,"updated":239,"__hash__":411},"blog\u002Fblog\u002Fexams-workspace.md","Nobody should draw an exam timetable in pencil",{"type":8,"value":253,"toc":395},[254,257,260,264,267],[11,255,256],{},"The exam timetable is drawn on paper, in pencil, by one person, in a week that nobody else wants.",[11,258,259],{},"Then a teacher goes on leave, one paper moves to the Thursday, and the whole grid needs checking\nagain by eye. Usually it is not checked, because checking it means reading forty rows against each\nother twice. So a class sits two papers at once in the third week, and everybody finds out in the\nhall.",[21,261,263],{"id":262},"a-series-checked-before-it-goes-out","A series, checked before it goes out",[11,265,266],{},"An exam series in 1410SMS is a set of sittings: a class, a subject, a date, a time, a room, an\ninvigilator. Building one is ordinary data entry. What makes it worth having is what happens next.",[69,268,273,279,285],{"alt":269,"height":270,"src":271,"width":272},"The Exams page with four tabs across the top, Exam Series, Builder, Reports and Settings, with Builder selected. To the right of the tabs an exam picker reads First Term Examination 2026\u002F2027, followed by a draft badge and the label Terminal Examination. Below, the series heading gives its term, session and dates beside a Publish and notify button; then a panel headed Worth checking before you publish, listing three amber Check findings and reading 0 to fix, 3 to consider; then the Generate the timetable panel, open at step one of four, Who is sitting.",1416,"\u002Fdocs\u002Fexams-workspace\u002Fworkspace.png",1832,[11,274,275,278],{},[37,276,277],{},"One action checks the whole series."," It reports every clash it can find, including the two that\nmatter most: the same class sitting two papers at once, and the same invigilator in two halls at\nonce. Clash detection runs on the weekly timetable engine's own logic rather than a second\nimplementation of it, so the two cannot drift apart and start disagreeing about what a conflict is.",[11,280,281,284],{},[37,282,283],{},"Publishing runs the same check and refuses on errors",", with the findings on the response rather\nthan a shrug and a support ticket. You cannot publish a broken series by accident.",[69,286,290,294,297,309,313,316,323,327,330,337],{"alt":287,"height":288,"src":289,"width":272},"A panel headed 'This timetable cannot be published yet' at the top of an exam page for First Term Examination, First Term 2026\u002F2027, dated 22 to 24 July 2026. It lists eleven findings, with '1 to fix, 10 to consider' on the right. The first carries a red Fix badge and reads that JSS 1A's Computer Science paper is on 2026-07-24, a day the school calendar says it is closed. Below it, amber Check badges list seven subjects JSS 1A takes that have no paper in the exam, and three papers with no invigilator.",936,"\u002Fdocs\u002Fexam-validation\u002Ffindings.png",[21,291,293],{"id":292},"publishing-is-its-own-permission","Publishing is its own permission",[11,295,296],{},"Building a draft and telling four hundred families are not the same act, so they are not the same\npermission. A member of staff can be given the series to build and not the button that sends it.",[11,298,299,300,303,304,308],{},"This pairs with the rule that makes drafts usable at all: ",[37,301,302],{},"a draft announces nothing."," Move papers\naround in a draft as much as you like and the world stays quiet. Move or drop a paper ",[305,306,307],"em",{},"after","\npublication and that class's families are told, because they have already written the old date in a\ndiary.",[21,310,312],{"id":311},"several-papers-move-together","Several papers move together",[11,314,315],{},"A cascade is the normal case. The Chemistry paper moves, so the Physics paper has to move to make\nroom, so the room booking changes.",[11,317,318,319,322],{},"Moving them one at a time through a clash checker means passing through arrangements that are not\nvalid and being told so at each step, which teaches you to ignore the checker. So a bulk move takes\nthe whole proposal and checks it against the series ",[37,320,321],{},"as it would be",", not as it is.",[21,324,326],{"id":325},"a-whole-series-can-be-generated","A whole series can be generated",[11,328,329],{},"If you would rather not place forty papers by hand, the workspace will do it, using the same\nconstruction core the weekly timetable generator uses.",[11,331,332,333,336],{},"You describe the shape you want, under ",[37,334,335],{},"Settings → Examinations",", rather than tuning six numeric\nweights: balanced, spread out, finished quickly, or mornings first. That distinction is most of the\nreason the feature is usable, because a scheduler that asks a bursar to balance six weights is a\nscheduler that gets used once. The weights are still there, behind a Custom option, for the school\nin fifty that wants them.",[69,338,343,347,350,353,357,371,374,378,381,388,392],{"alt":339,"height":340,"src":341,"width":342},"Step three of the generation wizard, What is in the way, with the four steps shown as pills reading Who is sitting, Which days, What is in the way and How to weigh it. Under a line saying what the engine needs in place, checked against this exam and the classes named above, a Re-check button sits on the right. The verdict reads Ready, with 1 thing worth knowing, above an amber note that JSS 1B has no pupils on its roll so no room can be checked against its size, and Back and Next buttons below.",542,"\u002Fdocs\u002Fexam-timetable-generation\u002Fgenerate.png",1754,[21,344,346],{"id":345},"a-paper-can-be-the-online-test-that-is-that-paper","A paper can be the online test that is that paper",[11,348,349],{},"If a subject is examined on the computer-based testing module, the sitting can be linked to that\ntest. The sitting then owns the test's window and its class list, so there is one thing to keep\ncorrect rather than two that must be kept in step.",[11,351,352],{},"On the phone that paper carries an \"Online\" tag, ahead of the room, which is still shown beside it.",[21,354,356],{"id":355},"four-documents-all-of-them-printable-from-a-phone","Four documents, all of them printable from a phone",[100,358,359,362,365,368],{},[103,360,361],{},"A class's papers, for the noticeboard and the parents.",[103,363,364],{},"An invigilator's list, so they know their duties.",[103,366,367],{},"A room's day, for whoever is running that hall.",[103,369,370],{},"The attendance roster a paper is registered on.",[11,372,373],{},"All four print from the mobile app as well as the web, which is not a box-ticking exercise. An\ninvigilator wants their roster on the way into the hall, not at a desk twenty minutes earlier, and\nthat is the whole reason it is on a phone.",[21,375,377],{"id":376},"one-naming-decision","One naming decision",[11,379,380],{},"Internally the object is a \"diet\", which is what examination boards call a round of exams.",[11,382,383,384,387],{},"Every screen a school reads calls it an ",[37,385,386],{},"exam series",", because \"diet\" is a word that costs a bursar\nthirty seconds and teaches them nothing. The technical term survives in our code and nowhere a\ncustomer looks.",[21,389,391],{"id":390},"what-stayed-on-the-web","What stayed on the web",[11,393,394],{},"Generation, the module's settings, linking a CBT test, and cloning a series or building it a class at\na time are web-only, deliberately. They are the parts done sitting down, once, with a spreadsheet\nopen. Everything done standing up, in a corridor, in the week of the exams, is on the phone.",{"title":219,"searchDepth":220,"depth":220,"links":396},[397,398,399,400],{"id":262,"depth":223,"text":263},{"id":292,"depth":223,"text":293},{"id":311,"depth":223,"text":312},{"id":325,"depth":223,"text":326},"Operations","2026-08-16","One person draws the exam grid, one paper moves, and the whole thing needs checking again by eye. Usually it is not. Here is the workspace that replaced the pencil.",{},"\u002Fblog\u002Fexams-workspace",{"title":251,"description":403},"blog\u002Fexams-workspace",[409,410,246],"exams","timetable","jFxF93HEcP_aRPykpnno8RN7mJtKB84r5Q-_-kMGy9o",{"id":413,"title":414,"author":6,"body":415,"category":233,"date":402,"description":517,"draft":236,"extension":237,"featured":236,"image":239,"imageAlt":239,"meta":518,"navigation":238,"ogImage":239,"path":519,"seo":520,"stem":521,"tags":522,"updated":239,"__hash__":525},"blog\u002Fblog\u002Fright-to-left-text.md","The bug that printed confident nonsense",{"type":8,"value":416,"toc":510},[417,420,423,427,430,433,436,440,443,449,455,461,464,468,471,474,482,486,491,494,498,501],[11,418,419],{},"A school sent us a report card and asked why the Arabic subject names came out as nonsense.",[11,421,422],{},"They were not nonsense. They were confident, well-spaced, correctly-kerned Latin letters, printed\nneatly in the place where Arabic should have been. That distinction is the whole story, because it is\nwhat made the problem hard to see from our end. It did not look like a rendering failure. It looked\nlike a school that had typed something wrong.",[21,424,426],{"id":425},"why-a-pdf-does-this","Why a PDF does this",[11,428,429],{},"The fonts built into the PDF standard are WinAnsi-encoded. They cover Latin and not much else.",[11,431,432],{},"Hand one of them Arabic and it does not draw a box, and it does not refuse. It takes each byte, maps\nit to whatever Latin glyph sits at that position in its own encoding, and draws that, at full\nquality. The output is a finished-looking document that nobody at the school can read.",[11,434,435],{},"A missing-glyph box would have been a better outcome. A row of boxes is obviously broken and gets\nreported on the first day. Plausible-looking Latin gets filed, and the school assumes the fault is\ntheirs.",[21,437,439],{"id":438},"three-separate-problems","Three separate problems",[11,441,442],{},"Getting Arabic onto the page needs three things, and skipping any one of them still produces a wrong\ndocument rather than an obviously broken one.",[11,444,445,448],{},[37,446,447],{},"A font that has the glyphs."," Without an embedded face that actually contains Arabic, you are back\nto the Latin substitution above.",[11,450,451,454],{},[37,452,453],{},"Shaping."," Arabic letters change form depending on what sits either side of them: initial, medial,\nfinal, isolated. Draw the isolated forms in sequence and you get disconnected letters. A reader can\ndecode it, in the way you can decode a word with the letters spaced out, and nobody would accept it\non a document their child brings home.",[11,456,457,460],{},[37,458,459],{},"Bidirectional ordering."," The shaper does not do this, which is the part most often missed. A line\nthat mixes Arabic with a pupil's Latin name or a numeric mark has to have its runs put in the right\norder first, and then the glyphs inside each run ordered by the shaper. Get it wrong and the mark\nends up on the wrong side of the subject it belongs to.",[11,462,463],{},"So the order is: work out the run order, then let the shaper order what is inside each run.",[21,465,467],{"id":466},"where-we-put-the-fix","Where we put the fix",[11,469,470],{},"At the single point where the platform creates a PDF document, not in each renderer.",[11,472,473],{},"A renderer that has to opt in to correct text is a renderer somebody eventually forgets, and the one\nthey forget is the certificate. Patching the one place a document is created means every PDF that\nlibrary draws got this at once: invoices, receipts, the family's own copies of both, the exam\ntimetable and our own subscription receipt.",[11,475,476,477,481],{},"Four of our documents render through headless Chromium rather than the PDF library, and they needed\nthe other half of the same problem solved: an inlined Arabic face, and ",[478,479,480],"code",{},"unicode-bidi: plaintext"," on\nthe elements that hold a school's own words. Those are the ones whose direction we cannot know in\nadvance, because they are whatever the school typed.",[21,483,485],{"id":484},"the-bar-for-shipping-it","The bar for shipping it",[11,487,488],{},[37,489,490],{},"A school with no Arabic gets byte-identical documents to the ones it got before.",[11,492,493],{},"That was the condition. A change to the text engine underneath every document the platform produces\nis exactly the sort of thing that shifts a margin by a point, re-wraps a line on someone's invoice,\nand turns into a fortnight of reports from schools who have nothing to do with Arabic.",[21,495,497],{"id":496},"if-your-school-teaches-arabic","If your school teaches Arabic",[11,499,500],{},"Nothing to switch on. Type Arabic into subject names, teacher remarks, class names or the head\nteacher's comment and it prints properly, mixed with Latin and with numbers on the same line.",[69,502,507],{"alt":503,"height":504,"src":505,"width":506},"A rendered report card PDF for Fatima Abdullahi of JSS 1A, First Term 2026\u002F2027. Four of her six subjects are named in Arabic and two in English, and the Arabic names sit right-aligned in the same column as Computer Science and English Language, each row carrying the same total, grade and remark. Both remark panels below are written in Arabic and set right to left: the teacher's runs across two lines and contains the numeral 91 and the Latin words Computer Science inside the Arabic sentence, each placed in reading order rather than at the end of the line.",2339,"\u002Fblog\u002Fright-to-left-text\u002Freport-card.png",1656,[11,508,509],{},"It pairs with the Hijri calendar option, which lets a school read and enter dates in the Umm al-Qura\ncalendar, the Gregorian one, or both, without changing a single stored date. Both are the same idea:\na school should be able to run in the language and the calendar it actually uses, and neither should\nrequire a separate version of the product.",{"title":219,"searchDepth":220,"depth":220,"links":511},[512,513,514,515,516],{"id":425,"depth":223,"text":426},{"id":438,"depth":223,"text":439},{"id":466,"depth":223,"text":467},{"id":484,"depth":223,"text":485},{"id":496,"depth":223,"text":497},"A school asked why the Arabic on its report cards was gibberish. It was not gibberish, and that is what made it hard to spot. What it takes to print Arabic properly in a PDF.",{},"\u002Fblog\u002Fright-to-left-text",{"title":414,"description":517},"blog\u002Fright-to-left-text",[523,524,246],"report-cards","internationalisation","hhNFq4YguQCpT35AUSKtoYrKGXURJ6UNf3aOCq1DCXY",1787681228821]