ClineAws

Application overview

ClineAws is an Android mobile app for keeping track of household chores in a flatshare. Each household shares a list of chores, and each chore is worth a number of points. When a flatmate does a chore, they log it in the app. A dashboard then shows the history of completed chores and how the points are split between flatmates, so everyone can see who did what.

Application logo.

Development context

I spent less than 20 hours on this project. The way the work was split is a bit unusual: I did all of the architecture myself (the client / server split, the network protocol and the messages exchanged, the database model and the choice of tables, how identity is handled, how the server is deployed and hardened, and the screens and their layout), and Claude Code wrote the code from those choices, with me reviewing it: the C# scripts, the networking layer, the SQL queries and the shell scripts. In short, I decide and validate the architecture, the AI types the code.

Login and account recovery

There is no password and no email address. On first launch, the user just enters a name: the server creates the account and returns a device_token (a UUID). That token is kept on the phone (PlayerPrefs) and sent again automatically on later launches. To log back into an existing account from another phone, or after the app’s data has been cleared, the only option is to type that same UUID by hand. So an account whose UUID has been lost cannot be recovered: all you can do is create a new one. That is a deliberate choice for an app between flatmates: it avoids any password handling and any guessable account identifier, in exchange for account recovery being impossible.

Technical architecture

The app reuses the architecture I had already used on ThousandsPong: a single Unity project that produces two builds. The client build (the phone) and the dedicated server build (#if UNITY_SERVER, on Linux) share the same networking code.

Server authority

All of the logic (account creation, household management, logging and cancelling a completed chore, computing the points) runs on the server. Messages go through custom Netcode messages (Netcode for GameObjects with Unity Transport), serialised in binary, with a RequestId tying each response to its request. The user behind an action is always looked up on the server, never read from the client’s request. In the same way, before touching a chore, the server checks that this user actually belongs to the household the chore is in. A household id or chore id sent by the client is never taken at face value.

Accounts and identity

On the server, a client is always recognised by its device_token (the UUID). That value is what authenticates a request, never the account’s numeric id, so that a number that is easy to guess cannot be used to pass for someone else.

Households

A flatmate can create a household or join one with a short invitation code: an integer picked at random in the range [0,10 000 000], easier to read out loud than a UUID. The code is assigned automatically on creation by a PL/pgSQL trigger, which also checks it is not already taken. Household membership is stored in a join table, foyers_utilisateurs.

Chores and completions

Each household has its own list of chores, each with a point value that can be adjusted. The app lets you log a chore as done or undo that (“Done” / “Cancel”), look at the history in a popup, and check the household statistics. How all of this is stored, and the choice not to freeze the points at the moment the chore is done, are explained in the Database section.

Database

The data lives in a PostgreSQL database running on the server. Only the server build talks to it, through Npgsql: the code that talks to the database is compiled under #if UNITY_SERVER, so it is not even present in the client. The connection string comes in through the COLOC_DB_CONNECTION_STRING environment variable, it is never written in the code. The starting schema is versioned as SQL migrations for the utilisateurs and foyers tables, and a setup-postgres.sh script sets up the database, the application role and its privileges (just SELECT, INSERT, UPDATE depending on the table). The taches and realisations tables were created by hand, outside those migrations.

There are five tables:

The history and the per-flatmate point totals are computed on the server, with queries that join realisations, utilisateurs and taches together with a GROUP BY.

Server infrastructure

The ClineAws dedicated server runs on the same personal server as ThousandsPong and gets the same hardening: the process runs as a systemd service (clineaws-server.service) under a dedicated user with reduced privileges, its settings (database, certificate) are passed to it through EnvironmentFile=, and a firewall limits the open ports. The domain name comes from DuckDNS.

The client and the server talk over WebSocket rather than UDP, so that a web build can connect from the browser. The server terminates TLS itself (wss://) with a Let’s Encrypt certificate: Caddy takes care of obtaining and renewing it, and a systemd path unit redeploys the certificate and restarts the service on every renewal. Clients connect straight to the server, with no reverse proxy on the path.

Download

The Android APK is available here: ClineAws.apk. Installing it requires allowing unknown sources on the phone.

A web version, which runs straight in the browser (including on mobile), is also embedded below: