You are browsing as a guest. Sign up (or log in) to start making projects!

StudyBuddy

  • 14 Devlogs
  • 51 Total hours

upload a practice test or worksheet, as a pdf or just a photo of the page, and StudyBuddy reads every question off it, works out what topic each one is, and after u mark which ones u got wrong it schedules them to come back using FSRS (the spaced repetition algo anki uses). the point is it tracks topics across every test u ever upload, so instead of "i got 12 wrong" u get "ur bad at ratios" backed by five papers. the vision model that reads the pages runs on my own rtx 5080 at home instead of a paid api. it dials out to the deployed site for jobs so theres no open port, and if my laptops off uploads just queue.

Ship #1 Changes requested

StudyBuddy

Turn the worksheets you have already done into a record of what you actually know.

Try it: https://trystudybuddy.vercel.app
Code: https://github.com/DagaVedant/StudyBuddy

What I made

  • Upload a worksheet you already finished, as a PDF or photos.
  • A vision model pulls out every question, its options and its answer key.
  • You mark what you got wrong. That is the only input it needs.
  • It sorts questions into 87 topics across SAT and competition maths.
  • Then it ranks your weak areas and schedules revision using FSRS, the algorithm behind Anki.
  • It also writes practice questions on your weak topics and exports misses to Blooket.
  • Built on my own past papers: 387 real questions from 22 worksheets.

What was challenging

  • The models can run in four places: my GPU, your API key, your own Ollama, or not at all.
  • A student with a GPU should never send homework to my server. A student with nothing should still get something.
  • Topic tagging needs an embedding model that serverless hosting cannot run.
  • So the shortlist is a pgvector query on the server and the vector is computed anywhere, including in your browser under WebAssembly.
  • Worst bug was three characters: I stored the global fetch on a class field, which passes the object as the receiver. Node allows it, browsers throw Illegal invocation. Every test passed and the only runtime that mattered was broken.

What I am proud of

  • It does not lie to you.
  • Weak topics are ranked by a Wilson lower bound, not a raw percentage, so two unlucky answers cannot fake a weakness.
  • Model-written questions are kept out of your accuracy, so the ranking cannot feed the questions it generates.
  • Every model response is schema-checked before it reaches the database.
  • Generated practice is sifted against thirteen specific failure modes.
  • When my GPU is off, the upload screen says so instead of spinning.
  • 1,459 unit tests, 84 end to end, 293 commits.

How to test it

  • Sign in with Google, or an email and password.
  • Upload any worksheet you have already done. A past paper works well.
  • Check what it read. Each question sits beside the page image it came from.
  • Mark what you missed, then open the dashboard.
  • The free trial reads three worksheets on my own GPU. If it is off, your upload queues and the app tells you.
  • To skip the wait, settings takes your own API key or connects to Ollama on your machine.

guys i wish this was markdown compatible but its not so sorry

  • 13 devlogs
  • 50h
Try project → See source code →
Open comments for this post

1h 12m 7s logged

ANYONE RATING THIS PROJECT - THE VIDEO ON TEH SHIP LOOKS A BIT DIFFERENT BECAUSE OF A QUICK CHANGE I MADE BECAUSE OF A SHIPWRIGHT SORRY

Devlog 12 - StudyBuddy

got everything ready to ship

  • turns out that ollama needed some permissions so fixed that and added it to readme for people to set up, and other stuff like that
  • shipping it in 5 mins

🎉 🎉 🎉 🎉 🎉 🎉 🎉 🎉 🎉 🎉 🎉 🎉 🎉 🎉

0
0
36
Open comments for this post

3h 50m 4s logged

Devlog 11 - StudyBuddy

this is a short one

  • got the google sign in to work
  • added email verification and forgot ur password thing
  • cleaned up the overall UI
  • made the topic tree standardized
  • cleaned up some of the extraction issues
  • added ollama integration for everyone
  • added practice question generation, topic overview, etc
  • tested everything fully
  • the attached image is the app after a ton of testing *
0
0
44
Open comments for this post

5h 35m 54s logged

Devlog 10 - StudyBuddy

mostly the same bug wearing different clothes: a screen that exists, that u can get to, that quietly does less than it says

tier C was sitting in settings doing nothing

  • save an ollama address and the app resolves u to a browser executor. that executor had nowhere to go, so ur worksheet just sat there looking queued
  • it claims the job now and reads each page against localhost:11434, posting back through the same queue my gpu posts through
  • has to run in the browser cuz a server cant reach ur localhost, so the tab stays open. checkpointed per page tho, closing it resumes instead of restarting the paper

a mark u mis-tapped was permanent

  • tap through 40 of these and ur going to hit the wrong one eventually
  • that one tap feeds the FSRS schedule, the topic accuracy, the weakness ranking and the blooket export
  • only way back was deleting the worksheet and uploading it again, which costs u a trial credit. so the fix for a mistap was paying for it

two defences that were never on

  • WORKER_ALLOWED_IPS was optional and empty meant no restriction
  • empty is the state every deployment starts in, so the normal outcome was a defence thats off that nobody ever decided to turn off
  • refused now. * still allows any address but somebody has to type it

untagged worksheets looked identical to broken ones

  • tier B cant auto-classify, the embedding model needs a native runtime the serverless host doesnt have
  • so ur questions saved fine and were reviewable fine, they just had no topic and nothing said why. reads exactly like it silently failed
  • every tier that can come back untagged says so now

nothing told u when a worksheet finished

  • u uploaded and then u guessed. sat on the status page or came back later and hoped
  • in-app bell that needs zero setup, plus web push for a tab u closed

also

  • “Review these now” now reviews those questions. the word had drifted onto three screens meaning three different things
  • dashboard was missing three of its panels, and the trend arrow was specified ages ago and never computed
  • taxonomy had no front door and the subject panel only went one level deep. Math > Geometry > Triangles walks now
  • pagination was capping at the fiftieth worksheet and saying nothing about it
  • the AI setup prompt showed up after ur trial ran out, which is the one moment it cant help u
  • grouped scripts/ by what it does to ur data. inspect/ reads, repair/ writes behind a guard, benchmark/ measures

1285 tests green. playwright hasnt run yet and app/ moved a lot this time, so thats next

0
0
24
Open comments for this post

4h 11m 13s logged

Devlog 9 - StudyBuddy

the merge tool could double up a question number

  • renumbering the survivor of a duplicate pair used Math.min of just those two rows, blind to the rest of the paper
  • merging a phantom #5 into a real #9 could hand the paper a second #5, the exact thing the tool exists to prevent
  • zero tests on a function that deletes rows. five now, including the repro

$15/hour was losing its sign, not just $5

  • the math-stripper runs from one $ to the next, so “earns $15/hour and $18/hour” reads the slash as a fraction and eats both signs. same with $40 = $25 + $15 on the =
  • i wrote this down once as “one weird case.” it’s the whole unit-rate and equation category
  • fix checks the char after the closing $: a digit means it’s opening the next price, not real math

figure crops didnt need a new pipeline, just reusing one

  • filed as “never produced,” which reads like crop, store, backfill
  • the verify screen already computes a crop window from the bbox over the stored page image. review got wired to the same math, every old worksheet gets it free
  • the real work was the guards: zero-area, inverted, off-page, or no recorded page size all have to degrade to nothing rather than to the wrong crop

a fence i built to be un-escapable, wasnt

  • the comment says a new tag can’t be added without going through the escaping. page-seam work added two by typing them directly
  • a page whose OCR contains the literal closing tag closes the fence early, and everything after reads as instructions instead of data
  • tag list exists once now, every fence built from it

every worksheets.status write was a bare UPDATE

  • no guard on the current value, so a stale job retry could drag an already-reviewed worksheet back to failed
  • one transitionWorksheet(from, to) now, every write through it

preview deploys were migrating the prod database

  • guard only checked VERCEL_ENV === 'production', but previews fire on every push against one shared DATABASE_URL
  • two finishing together were racing through the migration folder

9 tests could go quiet and nobody would know

  • one e2e file, 12 tests serial in a single tab, everything past “verify” depending on a question a drag gesture created three tests earlier
  • a drag regression silently skipped 9 unrelated tests instead of failing them
  • api fixture, split the file, broke the drag on purpose to prove it. held

the question list rendered all 114 cards for a screen that edits one at a time

  • deferred a while back: virtualizing editable rows risks one unmounting mid-edit
  • only one card can ever be expanded, so the risk surface is exactly one row
  • virtualizes past 40 now, open row pinned into the rendered range wherever scrolling goes. typed into one at 60 questions, scrolled thousands of px away, still there, still focused, still holding the edit

also

  • profile save had devlog 4’s router.refresh() remount bug
  • login rate limit skipped Auth.js’s own credentials endpoint
  • ollama worker had no startup timeout and just hung
  • worksheet text leaked into console logs on schema rejections
  • review screen shipped every page’s OCR text on page-1 load
  • admin console got merge, tree edit, queue, usage
  • doc-count drift (third time), and a false-positive LaTeX check flagging real set notation as broken math
0
0
24
Open comments for this post

3h 13m 9s logged

Devlog 8 - StudyBuddy

im too lazy to have a full write up for this (watched spiderman tdy IT WAS REALLY GOOD)

  • for each topic that a user gets wrong, a seperate model (gpt-oss:20b, sorry if i miswrote the model) gives a walkthrough of the topic

  • also added missed questions to the csv export

  • added a AI answer key system if the worksheet doesnt have one.

0
0
12
Open comments for this post

3h 0m 5s logged

Devlog 7 - StudyBuddy

the drag box was broken in the real app. for months

u upload a worksheet, u draw a box around question 1, it fills in. thats the whole manual editor, thats the whole free tier. and it didnt work. click through the app to get there and nothing responds. reload and its fine.

four previous commits went looking for this. the test had a 24 line comment explaining why it was probably a test problem. it was not.

elementFromPoint(100, 28)  ->  HTML
elementsFromPoint(100, 28) ->  [HTML]

thats the browser saying nothing is at this pixel, for every pixel on the page.

the cause was 8 view transition animations, 6 stuck running forever. one that never finishes sits in the top layer and covers everything. and its a pseudo element so it shows up in no ancestor walk and no element stack, which is why every previous investigation contradicted itself.

bisected on clean builds:

next flag react component result on on broken off on broken on off clean off off clean

so its react’s <ViewTransition>, not next. three lines of css. the drag test used to fake the mouse with dispatched events, now it uses a real one, which is the only thing that proves anything.

gemini has never completed a single request

4 providers in settings. one says “has a free tier worth starting on”. zero successful calls, ever.

  • every nullable field is anyOf: [{type:'x'}, {type:'null'}]
  • gemini doesnt understand anyOf, so a filter strips keywords it rejects
  • the filter dropped anyOf and left {} behind, while leaving the field in required
  • a required field with no type = rejected request. every time

funny part: the allowlist already had nullable in it, gemini’s own word for the same idea. someone knew. nothing connected them.

the landing page was lying about 3 of its 4 topics

theres a comment above them saying “kept honest on purpose: these are real taxonomy names”.

  • Ratio & proportion - not real
  • Linear equations - not real
  • Reading inference - not real
  • Vocabulary in context - real

so the one claim the page made about its own honesty was the false one lol. theres a test now instead of a comment.

tests found 2 bugs i wasnt looking for

  • new Date("sometime in 2010") returns jan 1 2010, cuz v8 scrapes a year out of almost anything. and it parses as local midnight while everything next to it is UTC. on a 13th birthday thats the whole question
  • one route answered 404 to someone with no session. the client sends u to sign in on a 401 and brings u back after, so a tab that sat open till the session expired just ate what u typed

the rest

  • a reload could cost u a 114 question paper. markup saves nothing till every question is marked, so its a local draft now
  • /, /signin, /signup are static html now. the topbar called auth() from the root layout, which made all 39 routes render per request
  • the 23mb embedding model was getting fetched inside a background task on every cold start, and failing silently
  • one commit recorded 32 renames and none of the code. the git add failed and i’d redirected the error away so i never saw it
0
0
46
Open comments for this post

1h 8m 16s logged

Devlog 6 - StudyBuddy

u can throw everything u got wrong into blooket now

  • button on the dashboard for the whole account, and one per worksheet if u only
    want that paper
  • it gives u a file, u upload it to blooket, u get a set of exactly the
    questions u missed
  • wrong means ever wrong, not currently wrong. if u got it wrong on paper and
    then right in review, its still in there. thats the one u actually want to
    drill and it wouldve been weird to leave out
  • blooket hands u an .xlsx template so everyone calls this an xlsx export, but
    its uploader only accepts csv. took a while to work out
  • also its importer just silently imports nothing if the file is slightly off.
    no error, no warning, zero questions. three separate ways to trip that

picking a subject barely did anything

  • theres a dropdown on upload for what subject the worksheet is. it offers
    things like “Algebra 1”
  • only the first bit of that was ever used, so picking Algebra 1 searched all of
    high school maths. exactly the same as picking “all of high school maths”
  • the one control u have over how ur questions get sorted, doing basically
    nothing

long papers were quietly losing questions to a limit

  • the topic tagger takes questions 100 at a time. fine
  • except it grabbed 100 in no particular order and then removed the ones already
    done, so on a 114 question paper 14 never got looked at, and which 14 was
    down to whatever the database felt like that day
  • worse on a second pass: if 100 were already tagged it handed back an empty
    list, which reads as “nothing left to do”, and the rest never got tagged at all

two screens counting the same paper differently

  • the worksheets page filters out page junk like “CONTINUE TO THE NEXT PAGE”
    before counting. the dashboard didnt
  • so the same worksheet was 25 questions on one screen and 26 on the other, and
    nothing tells u which one is lying

the chart was lying about time

  • the accuracy chart draws a bar per week. it was only making bars for weeks u
    actually did something in
  • so 12 bars looked like 12 weeks in a row but werent. practise in march and
    again in june and u see two bars side by side like it was steady
  • every week is a bar now, empty ones included, and it says which weeks its
    showing

scrolling changed my settings without me touching anything

  • the page range and question count boxes were number inputs, and number inputs
    treat the scroll wheel as a way to change the value
  • so scrolling down the upload page with ur cursor over one of them silently
    rewrote which pages get read
  • found a pile of other accessibility stuff while i was in there: buttons a bit
    too small to reliably hit on a phone, cards that vanish in high contrast mode,
    and a “skip to content” link that didnt actually skip anything

also

  • asking to see an explanation u already had was using up ur hourly limit for
    generating new ones
  • the topic picker was built in a way that made screen readers think the list
    had nothing in it
  • button labels were half Title Case and half sentence case, sometimes on the
    same screen
0
0
29
Open comments for this post

35m 16s logged

Devlog 5 - StudyBuddy

“accept the remaining 114” checked none of them

  • that button fires one save per question, and on my test paper thats 114 of
    them at once
  • nothing read the answers back, so a save that failed looked exactly like one
    that worked
  • the tick stayed on, u moved to the next screen, and it was never stored

deleting a question said “Saved” and then didnt delete it

  • delete waits a few seconds so u can undo it. it dropped the question from the
    list first and threw away whatever came back from the server
  • so if it failed u got told it saved, and the question showed up in ur study
    queue later like nothing happened
  • also there was no undo button anywhere. it was just a slow delete

$5 was being eaten

  • maths sometimes comes wrapped in dollar signs so i strip them off. money also
    comes wrapped in dollar signs
  • “Sam has $5 and Ana has $12” was being read as “Sam has 5 and Ana has 12”
  • checked a real saved question and yep. paper says $5, database said 5

if my worker died, ur worksheet said “queued” forever

  • the machine that reads the pages runs at my house. if it fell over mid job,
    nothing anywhere ever marked that job as failed
  • it just sat there, and the free credit it charged u never came back

the topic tagging could fail without failing

  • it needs a bit of software thats not always there on the server. when it
    wasnt, it came back with “no matches”
  • which is a completely normal answer. so the job finished, every question was
    untagged, ur weak areas page was empty, and nothing anywhere was an error

one i was told to do and didnt

  • had a note to cap the page number by how many pages the worksheet has
  • except if u upload pages 10 to 15 of a pdf thats six pages numbered 10 to 15,
    so that check refuses every single one of them
  • capped the two things separately instead

also

  • the screen asking u to check questions against the page never showed the page
  • finishing a review session stopped saying u finished it
  • the AI could print its own error onto ur status page, which sometimes meant
    quoting ur own worksheet back at u
  • the upload checked the image size by asking the browser instead of opening
    the image
0
0
38
Open comments for this post

2h 16m 50s logged

Devlog 4 - StudyBuddy

no new features today. just went hunting for stuff that was quietly broken, and
there was way more of it than i expected

the sign-in page could send u to a different website

  • if someone handed u a link like /signin?next=someothersite.com, u would log
    in and then land on their page
  • immediately after typing ur password, which is about the worst possible moment
    for that to happen
  • this one went first

there was no limit on login attempts

  • i had limits on signing up and on uploading. somehow not on the actual
    password box
  • so u could sit there and guess forever
  • getting blocked now looks identical to just getting the password wrong.
    telling someone “too many attempts” quietly confirms the account exists

file storage was writing into the void

  • if one setting went missing it silently saved ur page images somewhere that
    doesnt survive on the server
  • uploads said they worked. returned a success. images just gone
  • nothing errored anywhere, which is why it sat there so long
  • now it refuses to start up at all instead of pretending everything is fine

i almost broke my whole test suite fixing something unrelated

  • locked down two internal-only routes with what seemed like the obvious check
  • except my tests run against a production build, so that check wouldve locked
    the tests out too
  • caught it before it shipped, then wrote a test explaining it so future me
    doesnt helpfully undo it

added security headers and instantly caught myself

  • put them in report-only mode first so nothing could actually break
  • about 40 seconds later it flagged a script that my own analytics loads
  • the strict version wouldve blocked it in prod. i absolutely wouldve shipped
    that

one fix i deleted instead of shipping

  • had a note to add another check to the duplicate-question detector
  • actually tested it against real papers first, and it turns out it can never
    trigger. the answers on a maths paper are just “4” and “9” and stuff, way too
    short for it to match on
  • wouldve quietly made things worse

all tests green at the end of it. onto the next pile

0
0
14
Open comments for this post

6h 5m 57s logged

Devlog 3 - StudyBuddy

wrote a script that reads each papers own answer key out of the source pdf and diffs it against my database. so the paper grades me instead of me grading myself. those 14 sheets scored 1 of 14 the first time i pointed it at them. tonight theyre 14 of 14.

barely any of it was the model.

one paper stored 8 of its 15 questions. the model had read all 15

  • the log said dropped 6 unreadable question(s). a count. no reason. it said that for two days
  • made it print which field rejected the question and it told me on the first run:
choices.0.label: Too big: expected string to have <=8 characters
  • answer labels are capped at 8 chars, but the cap runs before the function that shortens them. that function only exists cuz the model returns A. 60 instead of A
  • so the cap was checked against exactly the thing the transform was written to fix. coordinate geometry paper, every option reads A. (-2, 3), ten chars, binned
  • a count with no reason cant tell u “model returned garbage” from “ur schema is stricter than the paper” and those have opposite fixes

also 44 duplicate-answer flags, every one wrong: -2 and 2 both normalised to 2 lol. on a maths paper the sign IS the question.

0
0
40
Open comments for this post

5h 15m 37s logged

Devlog 2 - StudyBuddy

HERE IS THE LINK TO TRY IT (https://trystudybuddy.vercel.app/)

  • left a pile of worksheets extracting overnight cuz i was sick of testing every fix against the same two papers. woke up to 9 worksheets, 713 questions, 353 pages
  • everything below only shipped after i swept it over all of that first. rule i have now, after two earlier “fixes” that read perfectly and were wrong on real data

a question that shipped reading ?rac{44}{11}

  • i tell the model to write plain text. it writes LaTeX anyway
  • sometimes that fails loudly. \sqrt isnt a valid JSON escape so the response explodes and i lose a page. thats fine?? at least i know
  • the other half is the problem. \f is a form feed and \t is a tab, both totally valid, so \frac{44}{11} parses perfectly and quietly becomes a form feed followed by rac{44}{11}
  • i had an AMC8 question in my database reading ?rac{44}{11} and nothing anywhere reported a problem
  • fix has to run before the first parse, not in the catch block, cuz the version that actually hurts u never throws
  • it doubles the backslash on letter runs JSON would misread, but only the six that collide (b f n r t u) and only when the run spells a real command. otherwise a real line break stops being a line break, which is a fun way to make things worse

questions torn in half by the page break

  • extraction reads one page at a time and never sees the page before or after. so a question ending at the bottom of page 3 with its answer choices at the top of page 4 is never whole in either request. five of them on the AMC8 paper
  • one fix folds the halves back together. the other is for the worse case where the extractor returned nothing at all for the second half, cuz a bare block of answer choices isnt a question so the model just drops it. theyre still sitting in the next pages text layer tho, u just have to go get them
  • sorting questions within a page needed its own module cuz the bounding boxes lie. question 4 came back with a top of 1428 and question 5 with 1379, so pure geometry puts them backwards
  • AMC8 went from 19 of 25 questions having their answer choices to 24 of 25, zero false positives across 348 SHSAT pages

stuff that broke

  • a worksheet told me it had 26 questions when the paper has 25. the extra one was the axis labels off a diagram, and the SHSAT ones had rows that just said CONTINUE TO THE NEXT PAGE. dropped 23 rows, all page furniture
  • then immediately shipped a followup bug where the card read “Questions 25” next to “Unchecked 26” cuz i filtered one count and forgot the other one lol
  • tried just asking the model to return a carried answer block as half a question. produced zero of them and started relabelling stem-only questions as free response, which hides the damage from every check i have. reverted

the landing page

  • every animation was gated behind prefers-reduced-motion, which sounds responsible until u find out some managed windows installs ship with animation effects off by default. so the page whose whole job is showing the product working was showing a static screenshot
  • the hero panel gets dealt onto the page like a card now. needs a perspective on the parent or the rotations collapse into a shear and it just looks like a slide
  • the forgetting curve draws itself left to right. stroke-dashoffset does not work here, pathLength is silently ignored under vector-effect: non-scaling-stroke so the dash tiles across the path instead of spanning it once. and i need non-scaling-stroke or the line renders 9x too thick. used a page-coloured shutter instead

next things: that one AMC8 question needs reading off the page image since the text layer doesnt have it. and theres a cheaper reduced-motion compromise i wrote down but havent built.

0
0
22
Open comments for this post

13h 43m 24s logged

Devlog 1 - StudyBuddy

 

so ive been doing SHSAT practice tests for a while and the thing that always got me is that after i mark one, i have like 20 wrong answers and no idea what to actually do with that info. like ok i got 12 questions wrong, but am i bad at geometry or did i just misread three questions? no clue. so id end up redoing entire sections i was already fine at.

 

basically what im building is a web app where u upload a worksheet or a practice test (pdf or even just a photo of the page) and it reads every question off it, figures out what topic each one is, and then after u mark which ones u got wrong it schedules them to come back later using FSRS (same spaced repetition algo anki uses).

 

the thing that makes it diff from just writing ur mistakes in a notebook is that it tracks topics across every test u ever upload. one test says nothing. five tests and it can actually tell u “ur bad at ratios” with a straight face.

 

the AI runs on my own laptop

 

i did not want to pay for an api. so the vision model that reads the pages runs on my own rtx 5080. it sits at home and asks the deployed site for jobs, and it only ever dials outward so theres no port open on my home network. if my laptops off, uploads just queue instead of dying.

 

the part i was most wrong about

 

i picked the model i was using (qwen2.5vl:7b) literally because it was the first one i pulled. thats the whole reason. so i finally benchmarked it properly, 9 models on a real 58 page shsat paper, 114 questions.

 

the one i already had won?? the 27b model is 4x bigger, scored 6 points WORSE, and took 183 seconds per page vs 7.8. id been assuming for weeks that upgrading would fix my accuracy problems lol.

 

also the grading was free which i was way too happy about. every question number 1-114 shows up exactly once on the paper so the test just grades itself, i never labelled a single page by hand.

 

the bug that was actually my fault

 

so when i looked at WHICH questions got missed they werent random, they came in chunks. one model dropped 17 questions in a row. turns out every single miss on every model was a page that came back completely empty. not a wrong answer. nothing.

 

and that was my bug not the models. an empty reply gives 0 questions and no error, so my checker (which only looked for gaps in question numbering) saw nothing wrong and the upload said success while a whole page just quietly disappeared. fixed with one retry at a slightly higher temperature cuz a model that decided to output nothing will decide that again if u ask it the exact same way.

 

stuff that broke

 

i wrote a check to catch questions that got cut off mid sentence (flag anything not ending in punctuation) and it flagged 25 out of 114 questions on a CLEAN run. all wrong. turns out shsat questions end with like “by” or “through” all the time and the answer choices finish the sentence. fixed it and it changed literally zero outcomes so the rule was doing nothing the whole time.

 

also added rate limiting and instantly locked myself out of my own test suite, which signs up way more than 5 times an hour from localhost.

 

also deleted my entire email system. u need a domain u own to send emails (spf/dkim records) and a free .vercel.app subdomain cant do that. so instead of buying a domain i deleted 274 lines and made google sign in the front door.

 

next things: tier B uploads dont get topic tags yet, and theres one test failing on purpose cuz FSRS says a question u just got wrong is due in 1 minute but i think it should be due immediately. gotta pick one.

2
0
71

Delete project?

Are you sure you want to permanently delete this project? This action cannot be undone.

All devlogs, followers, and associated data will be removed.

Followers

Loading…