Image & content pipeline
in productionProduct photos from the factory and clients' offices are reworked with Gemini into clean catalog shots; product descriptions are generated from raw parameters.
Order management for a furniture factory: the whole path of an order — client, payments, designers and drawings, production deadlines in working days, shipping, closing documents — plus purchasing, statistics and a photo library. Replaced the 2017 PHP/MySQL system whose spec I wrote as a sales manager.


Staff keep the entire order in one card: client and contacts, amount and payments, designers, files and drawings, a discussion thread with a rich-text editor, and a change log of who changed which field. Purchasing lives next to it: requests for materials per order or per workshop, suppliers with their assortment tags, invoices and files.
Management sees statistics on money, production, purchasing and managers. A separate module turns live product photos into catalog frames through Gemini and keeps all of the company's photos in one searchable library. It works on a phone too — cards instead of tables.
Also: 319 commits · 12 migration scripts from the old system · 20 permissions · 4 application services.
The assistant has to answer questions like "how many orders did a manager close this quarter", and writing an endpoint per question is endless. So the OMS hands out a text description of its schema and executes the SQL the model writes — behind six layers: a filter for one SELECT without dangerous functions; the real boundary, a PostgreSQL READ ONLY transaction (SERIALIZABLE, DEFERRABLE) that rejects even a write hidden in a CTE; a 5-second statement timeout; an outer LIMIT so the driver does not materialise the whole result; a separate small connection pool so a stuck query cannot starve the application; and always ROLLBACK. Access only by a service key compared in constant time.
Who may edit a field depends on global permissions and on the role in that particular order — its manager, its designer, a senior sales manager. The matrix "field → predicate" lives in one backend module and is used twice: to check a PATCH and to compute the editable fields returned with the card. The front end does not duplicate the rules: it makes the listed fields editable and sends only the diff. Permissions are an enum with fixed ids seeded by an idempotent migration and cached in Redis. The "in progress" status cannot be set by hand — it follows the first payment or a credit mark, and every automatic transition is written to the history.


The planned ready date is the date of the actual first payment plus the promised working days by the Russian production calendar. The calendar is fetched from isdayoff.ru by a background task once a day under a distributed Redis lock (the backend runs four workers), with the network call made before the transaction is opened, and a year that is not yet approved is simply skipped.

Twelve scripts run in strict order — users, clients, contacts, suppliers, topics, orders and so on to purchasing — translating old ids into new ones through JSON maps and reporting every skipped row with a reason. Values people were used to were kept. Production has neither Python nor MySQL on the host, so MySQL is started once as a container in the application network, the scripts run inside the backend container, and the container is removed.