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

Zee

@Zee

Joined June 2nd, 2026

  • 23Devlogs
  • 5Projects
  • 3Ships
  • 7Votes
Open comments for this post

5h 32m 25s logged

Devlog 16

I just boosted the security of the tool quite a bit, now with rate limiting, aggressive schema validation, and payload size limits. The issue before was that you could spam stuff no problem, but now there is a ton of resistance, and very strict limits. I still have more plans to make it even more secure as well. I also setup meta tags so now supposedly when you send a link depending on the platform, it will show this image and a description as well.

An example of some of the new aggressive schema validation is:

class QuestionChanges(StrictModel):
    title: Str | None = None
    type: (
        Literal["ln", "sn", "cb", "a", "img", "n", "mc", "sc", "r", "st"]
        | None
    ) = None
    opt: dict[Annotated[str, StringConstraints(pattern=r"^[0-9]$")], Annotated[str, Field(max_length=50)]] | None = Field(default=None, max_length=10)
    minmax: Annotated[list[Annotated[int, Field(ge=-99999, le=99999)]], Field(min_length=2, max_length=2)] | None = None
    stars: Annotated[int, Field(ge=0, le=10)] | None = None

I setup two different rate limiting systems, these include ones for the websocket, where each individual message type can get its own rate limit (some things should be easily called 500 times in a minute, while others should NOT be called more than 10)

@ws_limit(maxCalls=500, window=60)
async def handleUpdateTeamQuestion(
@ws_limit(maxCalls=8, window=60)
async def handleCompCodeChange(

Window being time in seconds, maxCalls being the max calls in that window.

This still needs more testing to make sure edge cases that are actually possible to do using the UI are not blocked by this security, but most regular use seems to not be affected.

0
0
14
Open comments for this post

5h 17m 26s logged

Devlog 15

I have now finished the following tasks:

  • Inviting members
  • Uninviting members
  • Kicking members out of group
  • Most of the UI to do with the member system (only joining a group left)

I have also added these improvements to the backend related things:

  • The front end no longer assumes that a user is in a group and instead calls a server endpoint to check first on sign in
  • The front end now connects on loading of the dashboard page instead of loading on the sign in page, which is to fix a current issue where if the user is already signed in but on the landing page, it makes them re-sign in, but soon it will just be a button saying “go to dash”
  • Added UI for loading hydration for dash
  • Made it so the add match/add team buttons were only visible to admins

I now pretty much don’t have too much to do, instead it will simply be finishing touches and a little bit of work with the joining system:

  • Make the UI for creating a group
  • Make the UI for joining a group actually work
  • Add rate limiting
  • Sync settings with database
  • Publish
0
0
57
Open comments for this post

3h 58m 59s logged

Devlog 14

I have now fully finished the summary team page UI as well. Now there are charts that show the points of each individual match, and then also each individual method of scoring.

I also added two new screens for when a team is in first or last, if a team is in first, then there are no teams above to accept/reject, so it shows a little bit of text, if a team is in last, there is no team below to pick, so they have a separate message.

I also took the time to add the flags bit beside a team’s name in the summary page too so it can match prescout.

With all of the above, I also completed the mobile UI equivalent.

0
0
94
Open comments for this post

8h 9m 34s logged

Devlog 13

ALL. SERVER. SYNC. IS. DONE.

I have finished every single piece of work needed to sync the server with the client at all times. I am now getting close to the finish line for this project.

I added info toasts for some new things, rather than just showing the success toast for an action a user may not have actually done themselves for things like adding teams and matches.

There are now very few tasks left really, they are:

  • Fully localize everything
  • Add French
  • Add mobile UI to summary
  • Add custom competition handling for summary
  • Add a favicon
  • Fix dark mode glitches on sign in/sign up pages
0
0
60
Open comments for this post

6h 9m 18s logged

Devlog 12

This devlog is now much more about the server side of things as that has been my focus right now.

The way this all works is I have a realtime python server connect to my database and all clients. Clients are put into a realtime channel with all their teammates. When the first user of a team joins, the python server pulls all that team’s scouting data from the database and keeps it in memory. This is to speed up request response times. When a second, third, fourth, so on, user of a team joins, the server instead just gives them the data it has in memory instead of the database. To keep this all in sync, the server updates its version of that group’s data as soon as it is successfully saved to the database.

It takes time to set this all up, and the parts of synchronization that I have completed so far are:

  • Competition code changes
  • Setting competitions to custom
  • Adding an individual team
  • Adding teams from API at the start
  • Adding an individual match
  • Adding matches from API at the start

I have done one thing for the UI though, and that is finally adding a 404 page. I designed this 404 with the magnifying glass in the middle as the 0.

0
0
13
Open comments for this post

56m 40s logged

Devlog 11

I usually space out my devlogs more, but I have now managed to get the base connection. This went by rather flawlessly due to now having the ability to use a python server for websockets, rather than the old system of having to use SQL requests with a million different RPC functions (sometimes causing queries to take up to 500ms on average) now taking only 100ms on average.

This uses a simple system to take the JWT token from the user, validate it from the server to find the user id, then checks the database to see what group the user is in, then checks the group to make sure that the user is actually in that group, and if all those conditions are met, the user will connect to the websocket.

If the user is the first one in the websocket, it right now just prints it, but it is designed to soon be used for a new feature. Soon, when a user joins a websocket and is the first one there, the server will load all that group’s data from the database, the reason for this is to have lightning fast connection and also make it possible to synchronize all users’ data in real time. (Whenever a user makes a change, it would update the server’s copy, and also push that change to the database)

0
0
42
Open comments for this post

3h 20m 57s logged

Devlog 10

I have now finished the skeleton UI for the summary tab.

I originally ran into some issues because I had tried to make one table with one map and just change the data for it, but that went horribly wrong because it made the code so janky and I had to write a ton of spaghetti code for it. In the end, I decided to switch to this system instead, where there are 3 completely separate tables for each tab, that get rendered in conditionally.

{currentTab == 0 ? (
    <Tab1
        sorted={sorted}
        sortBy={sortBy}
        setSortBy={setSortBy}
        setSortDown={setSortDown}
        sortDown={sortDown}
        selected={selected}
    />
) : currentTab == 1 ? (
    <Tab2 teamsBelow={teamsBelow} />
) : (
    <Tab3 teamsAbove={teamsAbove} />
)}

This way allowed me to have more freedom and more organization with the code.

I also originally ran into an issue with my rendering system for picks. When a team would set their pick order, originally to preserve the order they had in mind, the site would check all teams in the picks array, and if they were below, they would render them in. This caused an issue where if a team changed ranks through a competition, the teams below would change, and some might not render, which caused a problem in that the indexes for the reordering were off, and it would reorder the ones at the top that were not visible to the user. In the end I fixed this by simply filtering out and deleting the ones that were no longer a valid pick.

updateSummary({
    picks: [
        ...summary.picks.filter((pick) => below.includes(pick)),
        ...below.filter((team) => !summary.picks.includes(team)),
    ],
});

My goals now are to get a start on the backend part so that the main structure of the site can be complete.

The tasks that would be left after that are:

  • Polishing the summary page UI
  • Making the mobile UI for the summary page
  • Adding the new setting to set user’s team number by default so they don’t have to constantly set it from the tab
  • Landing page improvements
0
0
64
Open comments for this post

4h 48m 36s logged

Devlog 9

I have now done a lot of work in relation to the summary page, the hardest part is now pretty much done (the all teams page).

The parts left now are the top picks page, and the accept/reject page.

I have also done some work that isn’t specifically for the summary page too. Now, setting a competition will make it so the FTCScout api will actually pull the teams and matches in the competition.

The only steps left before synchronization now are those previously mentioned summary pages, and the mobile UI for all summary pages.

0
0
6
Open comments for this post

3h 24m 5s logged

Devlog 8

This is now where things are really starting to pick up. With the entire match scouting page done, there is now only summary, and then it is time to work on the synchronization.

I was thinking about leaving the score page empty, but instead I decided to just put what would be there for FTC Decode, I will later switch it to Biobuzz when the game is known.

0
0
3
Ship

I made a basic portfolio website with three sections, an about me, a tech stack, and a previous projects. (The about me section appears if you hover above the profile picture). I wanted to test a bit of my CSS and JS skills so I made a twinkling star background, along with the shifting gradient background. I also made a CSS infinite carousel that stops if you hover over it.

Try project → See source code →
Open comments for this post

1h 26m 2s logged

Devlog 3

I have now added two more sections, the Tech Stack section and the Previous Projects section. For the Tech Stack section I made an infinite css carousel, and for the previous projects I have a grid with an image, title, and description of each project.

0
0
4
Open comments for this post

1h 5m 41s logged

Devlog 2

I have now added a cool hover effect for the about me section, and also these links with a glow hover effect for github and hackclub profile

0
0
3
Open comments for this post

20m 39s logged

Devlog 1

I have now finished the moving gradient background to create a dynamic background, along with using js + css to make twinkling stars in the back.

0
0
3
Open comments for this post

3h 33m 50s logged

Devlog 7

I have now finished the team prescout page for both phones and desktop, this is where scouts can fill in those questions from earlier. I didn’t really run into much issues, but I implemented a special system to make sure that this fill in works with my current question structure.

The original issue

The original issue with this system is that if a question is edited, it keeps its question id, and if a user edits the question type, that means that what was once a multiple choice, can now be a note, which would completely mess it up if a user opens a team to check on the data. The solution? If a user enters a team page with an invalid question, the question will be reset to its default, so a string will be reset to “”, a number input will be reset to 0, etc.

Now this means the prescout page is pretty much completely done, and I now have to start on the match scouting page.

0
0
3
Open comments for this post

41m 24s logged

Devlog

I have now finished making my Slack Bot for FTC

I use the FTCScout API to get the info for the 3 main commands

/ftcbot-teaminfo (returns info about a team)

/ftcbot-compinfo (returns info about a competition)

/ftcbot-teamcomps (returns what competitions a team is going to)

There is also /ftcbot-help to see what commands are available.

I have now added it to a slack channel for testing.

0
0
2
Open comments for this post

1h 21m 38s logged

Devlog 6

I have now finished the phone UI for the prescouting page, meaning the last step of this page is officially complete. The next tasks are the individual team pages and the start of the match scouting page.

0
0
2
Open comments for this post

4h 53m 34s logged

Devlog 5

I have now finished the following tasks:

  • Ability to edit question extra fields (e.g. min/max of a slider question)

  • Ability to delete a section

  • Ability to add a section

  • Ability to edit a section

  • Ability to add a question

The tasks I have left related to the question management system are:

  • Translation keys

  • Create the phone UI

I also hit a small hiccup along the way of adding these features where I discovered due to my localstorage structure, whenever a competition is switched, the questions are all deleted (now fixed by not just using a blank localstorage.clear())

New Code

/**
 * Creates the base skeleton structure for localstorage
 *
 * @param {boolean} force - Force overwrite of existing localstorage or not
 */
export function createSkeleton(force: boolean) {
    const existing = localStorage.getItem("data");

    if (existing && !force) {
        return;
    }

    let setPrescout = {
        structure: {},
        sections: {
            "0": {
                title: "Section 1",
                headersize: 1,
                questions: [],
                index: 0,
            },
        },
    };

    if (existing) {
        const parsed = JSON.parse(existing);

        setPrescout.structure = parsed.prescout.structure;
        setPrescout.sections = parsed.prescout.sections;
    }

    const skeleton: LocalStorageData = {
        compkey: "",
        custom: false,
        prescout: {
            structure: setPrescout.structure,
            sections: setPrescout.sections,
            teams: {},
        },
        match: {},
    };

    localStorage.setItem("data", JSON.stringify(skeleton));
    resetAllStates();
}
0
0
3
Ship

I made a new tab page, so far, it has html, css, and js, it’s in a public repo, deployed on github pages, and uses duckduckgo api to fetch search results using a cloudflare worker.

This is just my starting point for this project as I want to go on and add many more features

Try project → See source code →
Open comments for this post

33m 29s logged

Devlog 3

Now I have fully finished the UI for search suggestions, and also added arrow key usage to go up and down suggestions

0
0
18
Loading more…

Followers

Loading…