MySQLManager.
A Flutter-based MySQL admin client — saved connections, browse databases → tables → rows, PK-safe CRUD, plus a free-form SQL shell; one codebase, five platforms.
01.Overview
The big pictureEvery DBA or backend dev hits this once: you are at a café and your boss pings "check the orders table, two rows are in a weird state". Opening a laptop and TablePlus is five minutes; phpMyAdmin needs a public port. I wanted a thin MySQL client straight on the phone — type host, port, user, log in, done. No proxy.
Mysql-manager-mobile is a Flutter app powered by mysql_client (a pure-Dart driver, no native binary needed) talking to MySQL directly over TCP. It saves connection profiles, auto-reconnects to the last one used, browses databases → tables → rows, edits rows by primary key, and ships a free-form SQL shell. The same codebase builds for Android, iOS, macOS, Linux and Windows — I now run it on an iPad for ~90% of my casual database check-ins.
02.Features
What it does- 01Saved connectionsList · edit · auto-reconnect last used
Each profile has name / host / port / user / password / autoReconnect. They live in one JSON file under
Directory.systemTempvia theSessionStore. On launch, if the last-used profile hasautoReconnect=true, the app connects right away — one less keystroke. - 02Three-level browserdatabases → tables → rows · pull-to-refresh
SHOW DATABASES→ database list;SHOW TABLES FROM <db>→ table list;SELECT * FROM db.table LIMIT 200→ row preview. Each level has its own icon (storage / table / row), native pull-to-refresh and breadcrumb-style back navigation. - 03PK-safe CRUDInsert · update · delete · LIMIT 1
The Insert form is generated from
SHOW COLUMNSwith a Set NULL checkbox per field. Update / Delete always carry a WHERE: primary-key columns first (Key=PRI), or every-column equality as a fallback. Every statement ends withLIMIT 1— no accidental whole-table updates. - 04Free-form SQL shellAuto-detect SELECT vs DML
The Query screen is a textarea + Run button. The service classifies:
SELECT / SHOW / DESC / EXPLAINrender as a horizontally-scrollableDataTable; everything else returns affected rows + last insert id. Parameters use named placeholders (:v_xxx); identifiers are backtick-escaped. - 055 platforms · 1 codebaseAndroid · iOS · macOS · Linux · Windows
Because
mysql_clientis pure Dart (needs only TCP), builds drop straight onto all five Flutter desktop / mobile platforms. Material 3 UI (teal seed#0D7A65); theDataTablescrolls horizontally so tablets feel great and phones still usable.
03.Tech stack
Tools used| App | Flutter 3.11 · Dart · Material 3 (teal seed #0D7A65) · DataTable + Scrollbar · TextField + AlertDialog |
| MySQL driver | mysql_client ^0.0.27 · pure-Dart TCP client · named parameters (:v_xxx) · IResultSet → row.assoc() / row.colByName() |
| Safety | Identifier backtick-escape (` → ``) · WHERE required on UPDATE/DELETE · LIMIT 1 on every mutation · _safeParam normalises column names to [a-zA-Z0-9_] |
| Storage | dart:io File JSON in Directory.systemTemp · ConnectionStoreState + ConnectionProfile (id / name / host / port / user / password / autoReconnect) |
| UX | Friendly errors: Android localhost → hint 10.0.2.2 or LAN IP · connection refused → hint bind-address + firewall · access denied → user/password / remote permission |
| Platforms | Android · iOS · macOS · Linux · Windows · one Dart codebase, no native plugin |
04.How it works
ArchitectureAll SQL lives in a single MySqlAdminService class holding one MySQLConnection?. Each screen calls 4-5 methods (getDatabases, getTables, getTableSnapshot, insertRow / updateRow / deleteRow, executeCustomQuery) and renders the result. Keeping it isolated means later swapping the driver (perhaps to mysql1 or a native FFI driver) does not touch any UI.
Updating a single row is the most important piece. updateRow calls SHOW COLUMNS to find any column with Key=PRI; if a PK exists, WHERE uses it, otherwise WHERE compares every column to its old value. NULL values are translated to IS NULL (never = NULL, which is always false). Every statement ends with LIMIT 1. If the WHERE somehow ends up empty, an Exception is thrown before MySQL even sees the query.
"UPDATE and DELETE never run without a WHERE. That is a rule the service imposes on itself, not on the user. A DB admin app on a phone — fat fingers, flaky network, dying battery — cannot afford to allow 'oops, I just UPDATE-ed the whole table'."
CaptchaOCR is a FastAPI micro-service that accepts a 4-digit captcha image in base64 and returns the corresponding integer. The ddddocr pretrained model is loaded once at process startup — every subsequent request is pure inference, with latency in the range of a few tens of milliseconds per image. The service is deployed via PM2 with auto-restart and a hard RAM cap, keeping it stable over long periods without manual oversight.
A NestJS API that auto-logs into ChatGPT via puppeteer-real-browser (Cloudflare anti-bot bypass), supports email OTP, persists the session for route /ask reuse and directly promt promt, and runs an hourly cron that pings Telegram when the session expires. This allows me to send prompts and receive responses directly through the API without needing to open a browser.

Hotel Management is an internal hotel administration system built for front desk staff and operations managers. The entire core workflow runs within a single system: accepting reservations from walk-in guests or online channels, handling check-in and check-out, recording ancillary services incurred during the stay, and automatically generating invoices at checkout. Permissions are scoped down to individual actions — receptionists, cashiers, and managers each have different screens and access levels. Every change in the system is written to a full audit log, with enough detail to trace back anything when needed.

RandomKit is a lightweight collection of randomisation tools that runs entirely client-side — no server, no data sent anywhere. It includes the tools people actually reach for: a customisable spinner with fair probabilities and transparent percentage display, duck racing, a draw lots picker, coin flip, dice roller, random number generator, password generator, and a random location picker on a map. The interface supports both Vietnamese and English, with clean SEO structure so each individual tool is independently discoverable.
05.Comments
Leave a few wordsNo comments yet.