Your own business logic can be rewritten without ever stopping the old system.
Chapters 2-03 through 2-11 covered the generic tools — the foundation, the gate, documents, code, mail, meetings, the public web. What remains is your own business logic: the substance of the core systems. That core is usually old. Written in Java or C#, riding on Oracle or SQL Server, understood in full by no one. We rewrite it through parallel operation and expose the logic as one API with FastAPI. The method is the sequence that ends with the old system stopped; the tool is FastAPI. In order.
"Don't break it" and "don't touch it" were advice from an era when rewriting was expensive
For a long time, the standard advice given to anyone responsible for a core system has been this.
"Don't break it." "Don't touch it." "Don't change something that works." "Use the legacy assets."
This was advice from an era when the cost of rewriting was prohibitive. When a rewrite took years and millions of dollars, "don't touch what runs" was indeed the right answer.
The era has changed.
AI translates business logic into Python. AI writes out the intent of SQL as Markdown. AI generates test data. AI extracts rules from code that has no documentation. The cost of rewriting has fallen by an order of magnitude.
Saying "don't touch it" at that cost is ignoring the new reality. There is no longer a reason to keep the old system.
Parallel operation kills the risk by measurement
The cost has come down, but the risk is not zero. No method can guarantee that a new system behaves exactly like the old one.
That is what parallel operation is for.
Build the new system with AI. Leave the old system running. Feed the same input to both. Compare the outputs.
Java/C#
Oracle/SQL Server"] New["New system
FastAPI
PostgreSQL"] Diff{"Compare every day"} Fix["Fix the new
leave the old alone"] Kill["Stop the old"] Input --> Old --> Diff Input --> New --> Diff Diff -->|a diff appeared so chase the cause| Fix Fix --> New Diff -->|zero diffs continued and the new is proven| Kill classDef good fill:#e8f5e9,stroke:#7a9a6d,color:#3a4d34 classDef bad fill:#fef3e7,stroke:#c89559,color:#5a3f1a class Old bad class New,Kill good
If the two outputs match, the new system is correct. If they do not, one of the two is wrong. Usually what surfaces first is a bug that has sat in the old system for years. A bug that was never written in any document.
Keep this up for the period you decided in advance. When the diffs reach zero and the unexpected cases have been covered, stop the old system.
Parallel operation is a way of crushing rewrite risk by measurement. Not a desk check. Not a spec review. Running it in production, on real data, and confirming.
Decide the day you stop the old system in advance
Decide the parallel period before you start. For a monthly process, "stop after three consecutive months with zero diffs"; for a daily one, "stop after the agreed number of zero-diff days" — write the stopping condition down as a number.
If you cannot stop once that condition has passed, the new system is not actually correct. Fix the new system. Do not run parallel operation "indefinitely."
Inside an organization, a psychology sets in: keep the old system around just in case. Here lies the problem. Keep it, and this is what follows.
- Operating cost doubles
- The people responsible are split across two systems
- When something breaks, arguments erupt over which side is at fault
- New features are needed in both, so the amount to write doubles
- The decision to stop the old is postponed forever
Parallel operation is a means, not an end. Once the new is proven correct, stop the old.
If you cannot stop it, you should not have started the rewrite. When you do it, do it.
"Use the legacy assets and augment them with AI" — in the end, this is a way of thinking that permits the old system to remain. New features pile up on the outside while the substance stays old. The years pass, and the organization is still not AI-native. Half-hearted coexistence freezes an organization. "Augment" was allowed back when rewriting really was too expensive. That is no longer the case.
Vendor products are stopped by the same move
Oracle, SAP, Salesforce, the Microsoft business products — these are not selling a "product." They are selling the situation in which you have to keep using the product.
The sequence for getting out by parallel operation goes like this.
- Export data from the product every day (the product keeps running)
- The new system, written with AI, processes the export and runs the same business
- Compute the same business figures (sales, inventory, customer state) in both
- When the numbers match, do not renew the product contract
- Take one final "full data export" from the product and move over completely
Time it to the contract renewal date. That is a strategic schedule. Count back from the renewal date — the parallel period plus the time to decide — and set the day you start.
The vendor will play every card to hold you — "migration risk," "data integrity," "you will lose the veteran who knows it." If parallel operation is producing the same outputs, all of them can be answered. The evidence is in your hands. The license fee is written in the contract. That is what stops.
Push business knowledge out into Markdown all at once
As preparation for parallel operation, push the business knowledge into Markdown. Do it in one sweep.
Old common sense held that documenting business knowledge was a project of months or years. Someone writes a little at a time in spare hours. Before half of it is done, the person who was writing transfers to another department. It stalls partway. In the end, it never gets written.
The era has changed.
Hand the AI everything — the old system's code, its comments, its SQL, the operating manuals, the past incident reports. Ask it to extract the business logic and organize it as Markdown. The first draft comes out at a speed that is orders apart from a person writing in spare hours.
It does not have to be perfect. A first draft is enough as a starting point. What is missing shows up as output diffs during parallel operation. Resolve those one by one and the business knowledge completes itself.
This is also the hidden benefit of parallel operation. *Business rules that were never written down all get flushed out by the parallel run.* Rules that appear in no desk-written spec, that only real operation reveals, are drawn out both from the AI's first-draft Markdown and from the output diffs of the parallel run. Taking documents back onto your own side was the subject of 2-07. The core system's business knowledge, too, lands as readable material in the same way.
Business rules live on the floor — the floor writes the tests
Who does the rewriting?
Old common sense went like this. The IT department, the SI vendor, or a consultant interviews the floor for requirements and writes the code. When it is written, the floor runs acceptance tests. This was the shape of an era when the knowledge needed for a rewrite was scattered. The ability to write code sat in the IT department; the knowledge of business rules sat on the floor.
That is no longer the case.
The ability to write code is held by the AI. What remains is only the knowledge of the business rules. And the people who know those rules most deeply are the people who run that business every day. The people on the floor have the AI write the code. That closes the loop. No relay of translators in between.
What matters in parallel operation is finding the output diffs. Does the new system produce the same output as the old? Judging that takes test data. And the people best suited to producing that test data are the people on the floor.
"July billing closes on the 10th, but we extend it to the 5th of the following month to allow for the Obon holidays" — Obon is the mid-August period when much of Japan takes leave, and the floor is where that rule is known. That person asks the AI: make billing test cases that account for the July Obon extension. The AI makes them. They are run through the old system to produce the expected output. That becomes the test data.
A rule that was in no desk-written spec takes material form as a test. Business knowledge flows from the floor into tests, and from tests into code. This is a test the IT department cannot write; the rules are on the floor. Rewrites have failed because people who did not know the rules were writing the tests.
Stop outsourcing
Once you get this far, the conclusion is plain.
There is no need to outsource a core-system rewrite to an IT vendor or a consultant.
The traditional grounds for outsourcing were two. First, the ability to write code existed only outside. Second, the knowledge of business rules had to be conveyed to the outside. The AI has settled the first. The second no longer needs to happen at all: the floor and the AI close the loop between them.
Vendor fees are the single largest cost item in a core-system rewrite. That goes away. The people on the floor who know the business rules have the AI write the code, have the AI write the tests, and verify by measurement through parallel operation. A rewrite stops being something you outsource and becomes something you do in house. The people who know the business use the AI to rewrite their own business. That is the new practice on the floor.
This is not a shrinking of the IT department's role. The IT department can concentrate on the base that supports the floor-and-AI teams: infrastructure, databases, deployment environments, security. It sheds the duplicated role of acting as intermediary for business logic.
Replace the DB by parallel operation too
The database gets replaced by parallel operation in exactly the way the logic layer gets rewritten into FastAPI.
Keep the database. But drop the vendor dialect. SELECT, JOIN, GROUP BY,
window functions — standard SQL has run since the 1970s and will keep running.
The AI writes it completely. Keep the standard SQL, drop the vendor dialect. That
line is the crux.
Oracle's PL/SQL and Microsoft SQL Server's T-SQL get dropped. They are vendor-specific dialects. Embedding business logic inside the database was how the last stronghold of vendor lock-in got built. Business logic embedded in a PL/SQL stored procedure gets rewritten in Python. Hand the AI the PL/SQL and it extracts the business rules and translates them into Python. Business logic comes back out of invisible stored procedures and into code. It becomes readable, version-controlled, testable.
The database itself moves to PostgreSQL. This too is parallel operation — sync daily from the old database into PostgreSQL, with the new system (FastAPI) reading and writing PostgreSQL while the old system reads and writes Oracle or SQL Server. Confirm the two are consistent by comparing outputs, and when it is stable, stop the old database. Dropping Oracle or SQL Server is the graduation certificate from vendor lock-in.
DDL dialect conversion, and the concrete migration steps using Azure SQL and pgloader, were covered in detail in 2-03. In this chapter you only need to hold the judgment: keep standard SQL, pull out the dialect and the logic. Rewriting only the logic layer escapes the lock-in halfway. Migrating to PostgreSQL is the last step out. And the license cost that stops is in the contract. Set it beside the new system's development cost, and the reason not to rewrite disappears.
The way out of every lock-in is the same
Everything covered so far has the same structure.
- The Java / C# logic layer, replaced by FastAPI (Python)
- Oracle / SQL Server, replaced by PostgreSQL
- PL/SQL stored procedures, replaced by Python functions
- SAP / Salesforce, replaced by systems you build
- Outsourcing to IT vendors and consultants, replaced by the floor and the AI
These are not separate problems. One move escapes all of them — rewrite by parallel operation.
Do not stop the old. Build the new beside it. Feed the same input to both and compare the outputs. When the diffs vanish, stop the old. Time it to the contract renewal date. Lock-in is a psychological device that makes you believe you cannot touch it and cannot leave. Parallel operation dismantles that psychology physically. Without touching the old, you build a new mainstream alongside it. Once the new runs, it becomes obvious to everyone that the old is not needed.
The rewritten core rides on the foundation and the gate
The new system's logic layer — the rewritten core logic — is exposed with FastAPI as one API. Why an API? To gather the core logic (inventory, ordering, pricing, and the rest) in one place instead of scattering it across screens. The form on the public web (2-11) and the in-house apps call the same API, and the duplication disappears. In Python, with FastAPI, AI writes it fast, and types and automatic documentation (OpenAPI) come with it.
The API reads and writes the PostgreSQL from 2-03 and verifies identity with the token from the gate (PocketBase) of 2-05. No new base is needed; it rides on what is already there.
# FastAPI — check the gate's token, query the foundation (DB)
from fastapi import FastAPI, Depends
app = FastAPI()
@app.get("/orders")
def orders(user=Depends(verify_token)): # the 2-05 gate confirms who this is
return db.query("SELECT * FROM orders WHERE user_id=%s", [user.id]) # the 2-03 DB
You do not turn the whole core into an API at once. Start with the operations used most, one at a time. Write it in dialogue with the AI and confirm it against the running system (the same way as VBA to Python in 2-04). This is nothing but running the logic of parallel operation at the granularity of a single API. Heavy processing is handled by Python behind the API, which returns only the result.
The code lives in the Forgejo of 2-06 and is called from the public web of 2-11 and from the in-house apps. The core logic rewritten by parallel operation lands, at the end, as this single API.
The first one can be the booking intake
You need not start with the core. The booking intake handed over from 2-09 holds this chapter's shape in miniature. Five decisions.
- Slots and bookings live in the PostgreSQL of 2-03
- Events are written to the Radicale of 2-09 over CalDAV, and appear as they are in Thunderbird and on phones
- The confirmation and the day-before reminder go out through the mail of 2-08; for a meeting, the Jitsi link from 2-09 is attached
- Identity is confirmed first by the gate's one-time code, as in 2-11
- The screen is the static page of the public web (2-11), which calls this API
@app.post("/bookings")
def book(slot_id: int, user=Depends(verify_otp)): # 2-11 — only people confirmed by the one-time code
db.execute("INSERT INTO bookings ...", [slot_id, user.email]) # 2-03
caldav.put(event_for(slot_id, user.email)) # 2-09
mail.send(user.email, confirmation(slot_id)) # 2-08
One function sits on the foundation, the gate, the mail, and the calendar. That is what "writing on top of what you stood up" means. The core's own API grows in the same shape.
Example: replace the monthly closing batch by parallel operation
Consider the closing batch that runs at month end.
Old: a batch written in COBOL or Java, running for years. No one fully understands the inside. It runs at month end. If it fails, accounting stops.
Week one: export a year of the old batch's input (the previous month's transaction data) and output (the closing summary). Treat this as ground truth.
Week two: hand the AI the old code and the operating documents, and have it write equivalent processing in Python on FastAPI. Run the year of data through it and check whether the output matches the ground truth. Resolve the places that do not match.
Weeks three to six: at the production timing when the old system runs, feed the same input to the new system as well. Compare the outputs every month. Where a diff appears, identify the cause and fix it.
The month you decided: when zero-diff months have run for the agreed count, the person responsible decides — from next month, operations run on the new system. The old batch is stopped.
The load on the people responsible doubles only during the parallel run, and lightens once it ends. And the business logic ends up readable in both code and Markdown.
Example: getting out from under SAP shipping
A mid-sized manufacturer runs shipping management on SAP.
- Data layer: a nightly batch exports shipping data from SAP to Parquet (Parquet and DuckDB, from 2-03) — SAP itself is not touched, only read
- New logic layer: stock matching, shipping decisions, and carrier routing are written in Python with Polars and DuckDB (the AI produces the first draft from floor interviews and screenshots of the existing SAP configuration screens)
- API and screen layer: the shipping instruction the floor uses is exposed as an API with FastAPI (this chapter) and rendered as HTML. Since it runs on the internal LAN only, it can be hosted on the machine of 2-02
- Reconciliation: compare SAP's shipping results with the new system's every day. Where there is a diff, chase the cause together with the AI. Undocumented rules turn up on the SAP side again and again
- The day you decided: once the diff has stayed at zero for the agreed number of days, promote the new system to production and stop SAP before the next contract renewal
The result is this. The license fee disappears. The business logic comes out into Markdown and Python (the SAP "business consultant" is never needed again). Customization happens on the floor the same day, where until now it meant asking the SAP vendor and waiting.
This is the core-system version of 2-07, taking the content back onto your own side. Do not drop it all at once; get out in parallel. "Don't drop SAP all at once — get out by parallel operation."
The numbers are in your own contract and your own quote
Only two numbers matter when deciding whether to rewrite, and both are already in your hands.
- The license fee you pay now — it is written in the contract. Stop the product and this stops
- The quote for the rewrite — if you outsource, get a quote from the vendor; if you do it in house, it is the time the people responsible give to the parallel run
Set the two side by side and you decide on your own company's numbers. Market rates and other companies' cases are not needed. How many undocumented rules the parallel run turns up is also a number that becomes yours once you rewrite.
To see a small business system whole, there are worked examples in public
repositories — seminar-kit
(aiseed-dev/seminar-kit: training
and seminar management, where an xlsx form is the only form definition and the
pending queue is a mailbox) and mfg-kit
(aiseed-dev/mfg-kit: quotes and orders
for a manufacturer). Both stand on FastAPI, plain SQL, and Flet — the manner of
this chapter.
The territory you don't build sets the outer line
The boundary is part of the spec too. Accounting, payroll, and tax are bought, not built. Domains wired directly into national institutions are the opposite of company-specific; they are generic across the whole of society, and for the same reason as the OSS-first rule of 1-05, they belong on the side where you use a proven off-the-shelf product. This is the outer line of this chapter's principle that you rewrite only your own business logic.
Printed forms are one shape of the exit. For an invoice or a delivery slip, FastAPI emits the data and merges it into a template as a PDF — the "exit" of the entrance, contents, and exit of 2-07, and boilerplate code an AI can write. No dedicated forms product is needed.
An approval flow is not a product either. Request, approve, finalize is a few lines of business rules (who, from what amount, with whose approval), a few dozen lines of an API that holds state, and a notification mail (2-08). Buying a workflow platform was the answer of an era that could not write code.
One last check before the old system is folded up: statutory retention. Ledgers and invoices carry retention periods, and the period is one line in the business-rules Markdown. Before the parallel run ends and the old system is stopped, confirm that the data subject to retention sits complete in your own database and files. Audit records too — on a box in your own hands, the logs are all there. No product is needed; only the rules are.
Before you build a screen, hold on to four design basics and no more
The rewritten core has landed as an API. What remains is the screens. The tool can simply be Flet (declarative UI in the same Python as the API, 2-04). The tool is not the problem. The problem is that nobody outside front-end engineering was ever taught design. So they cannot judge whether the screen the AI produced is good or bad, and all they can say is "make it look nicer."
You do not need the skill of drawing. You need a vocabulary for seeing and naming. There are only four basics.
- Proximity — related things go close together, unrelated things go apart. A screen whose items look scattered has broken this distance
- Alignment — line the edges up. If it is left-aligned, everything is left-aligned. A screen that is not aligned looks careless on that alone
- Repetition — the same role gets the same shape, repeated. Buttons and headings that change color and form from screen to screen are a lack of repetition
- Contrast — what matters is larger and darker, everything else smaller and lighter. A screen where everything is the same size conveys nothing
Two more, and that is all. At most three colors (background, text, and one accent), and one or two typefaces. When in doubt, remove rather than add.
With this vocabulary, the instructions you give the AI change. Not "make it look nicer," but "the proximity between the label and the input field is weak," "the button color is not repeating," "strengthen the contrast on the total amount" — instructions that can be acted on as written. Design knowledge works not as a skill of drawing but as a vocabulary of judgment.
And beyond the four principles, most of design is made of rules rather than taste. Spacing is taken in fixed steps (multiples of 8, for instance). Font sizes are decided as a small scale and reused. Contrast between text and background has standard thresholds (the accessibility norms). A button is shaped to look like a button. An action that cannot be undone gets a confirmation step. Every one of these is a convention, not a matter of taste.
If they are rules, they can be written. In the same way that business rules were pushed out into Markdown, the design rules can be fixed on a single page — the spacing steps, the type scale, the three colors, the component shapes. Hand that one page over with every screen request and the AI applies the same rules to every screen. Repetition is enforced automatically.
The strongest single rule is the grid. Cut the screen into equal columns (twelve, usually) and place every component on a column boundary. That is the whole rule, and that one rule enforces most of alignment and repetition by itself. Web and app designers tend to dislike the grid as rigid and boring — to a trade that sells originality, a lattice looks like a cage. But what a business screen needs is not originality. It is predictability: the same thing in the same place on every screen you open, and nothing supplies that more cheaply than a grid. Better still, the column count and the gutters are numbers, which makes the grid the design instruction that reaches an AI most precisely. The gain is not only visual either — a grid fixes the layout. Because the positions of the components are decided before the content arrives, the renderer does not have to recompute the arrangement to fit the data that came in, the display is fast, and nothing jumps around while loading. The discipline becomes performance.
The worry that fixing the layout will hurt when the content stops fitting is a memory of paper. Paper has a fixed area, so content that does not fit really is a problem. A screen is different. It is smaller than paper to begin with, so showing everything at once was never possible, which is why the machinery for expanding — scrolling, collapsing and unfolding — comes as standard. Only the placement is fixed, and content that grows is expanded when it is needed. The case where fixing hurts never reaches the screen.
Besides, the floor knows the grid well already. Shrink Excel's cells into small squares and compose a form against the frame — this is what Japan calls kami-Excel, graph-paper Excel. The IT industry has long called it the worst case of data a machine cannot read. But "cannot read" is not accurate. Kami-Excel is read by plain Python — the content sits inside a structured file from the start, and a few dozen lines of script lift it out of the boxes and into a table (writing that script is now the AI's job, and the preparation work of 2-15 is exactly this). The graph paper's real virtue lies elsewhere. *As long as everything snaps to the squares, an amateur can build it and an amateur can fix it.* Move one box, add one column, and the form changes. A tool the floor can build and fix for itself removes the need to order development. Nobody taught the floor to do this; laying out a form, they reached for graph paper anyway. The instinct of snapping every box to a lattice was right all along. Grid design inherits that instinct as it is — the frame goes to the screen's grid, the content goes to the database. And the graph paper's real virtue, that an amateur can fix it, carries straight over to the screen. You move the content not because it cannot be read, but because putting it in a database once is cheaper than digging it out of the boxes with a script every time. That is the whole reason. To designers it looked like a cage, to the floor it looked like graph paper — the same lattice. So the amateur uses a grid layout. For the reader of this chapter, there is no fitter default.
The one-page rule sheet starts with this line: "12-column grid, spacing in multiples of 8, input forms 6 columns wide."
Because the territory is made of rules, AI can do design. The common screen patterns, the component shapes, the ways of taking spacing — the conventions are already learned, and asked for a screen it produces a standard, sound one. Even the one-page rule sheet can start as an AI draft.
What the AI cannot do is original design. Its output converges on the average it learned. A look no one has seen, a new style that defines a brand — that does not come out of an AI. But a business screen does not need originality. What the floor uses without hesitating is precisely the familiar standard form. Where originality is required — a brand, a storefront, design that is itself the product — the human brings in the defining image. Business screens hold up without a designer exactly because no originality is required there.
And it is not only design that needs no originality.
Everyone but the professional designer uses generic design patterns. Everyone but the professional programmer combines OSS libraries. Everyone but the professional writer writes plain prose. Originality is a profession, not a default.
Originality belongs to the trades that sell it. Where it is not the product, the shared convention is fastest, cheapest, and least breakable — and because conventions sit at the center of what was learned, they are what an AI reproduces most reliably. Assembling OSS parts (1-05), writing business rules in plain Markdown (this chapter), snapping screens to a grid — all of it is one and the same practice.
Two challenges do come up in practice, and both are taken with the same move: rules.
The first is the diversity of screens. PC, tablet, phone — the widths vary, and building a screen per device never ends. Take this with rules too. Fix two or three width steps (narrow means one column, wide means two columns plus a side rail) and add the arrangement for each step to the same one page. With a grid in place, that addition is one line about dropping the column count: wide widths get 12 columns, narrow widths get 4. Flet ships the same code to desktop, web, and mobile, so handling diversity stops being the job of building a screen per device and becomes the job of adding a few lines of rules.
The second is Japanese fonts. CJK fonts carry thousands of glyphs, so they are heavy, the choices are few, and the good ones cost money. That was the problem for decades. It is no longer the case. Some of Morisawa's UD typefaces — universal-design faces built so characters are not misread — are free to use. BIZ UD Gothic and Mincho ship with Windows and are served from Google Fonts. On the rule sheet, one line does it: body text in BIZ UD Gothic, otherwise the system font. This site's own body text is set the same way: the UD faces where the device has them, the system faces otherwise.
Design practice in full, diagrams and slides included, is covered in the next chapter (2-13).
Most of design is rules, not taste. Rules can be written down and handed over — exactly like business rules.
Before going live, run four checks
Before any moving part goes outside, run four checks. They belong in the "verify" step of 2-11's "build → verify → deploy," every time. Record the result in the design document. The AI may help with the searching; matching the table against the implementation and deciding is the human's job.
The four are not exotic failure modes. In the OWASP Top 10 for 2025, broken access control is #1, cryptographic failures #4, injection #5, and mishandling of exceptional conditions #10 (OWASP). In MITRE's 2025 CWE Top 25, missing authorization is #4 (up from #9 the year before) and authorization bypass through a user-controlled key — fetching someone else's record by its ID — is #24 (MITRE). Both checked 2026-10-07. The four checks map straight onto the top of those lists.
First — confirm the permissions on every API
- List every FastAPI route and every PocketBase collection. In the design document's table, write for each route who may call it (public; confirmed by one-time code; logged in; the owner; an administrator). Match the table against the implementation, and delete any route not in the table
- When you add a route, re-check every existing route. Apply authentication per router, so that forgetting it fails toward "deny"
- An API that takes an ID compares the record's owner with the token's user. Write a test that confirms someone else's ID cannot be fetched
- Check all five PocketBase rules: list, view, create, update, delete. An empty string means "anyone"; null means "administrators only." To restrict to the owner,
owner = @request.auth.id - For the one-time code (2-11), check the code's expiry, rejection of a code already used, and the limit on attempts
- Hiding a button in a Flet screen does not count as a permission check. The API side denies
- Search for bypass routes left behind: names like
bypass,debug,test,dev, and branches that drop authentication underif DEBUG - Check that an exception does not fail toward "allow." If token verification raises, deny rather than pass
Second — how input is handled
- Never build SQL by string concatenation; pass parameters. Search for SQL assembled with f-strings or
+ - Never embed user input directly in a PocketBase filter. Use the SDK's parameterized filter
- For output into HTML, use
textContent, notinnerHTMLordocument.write. Keep Jinja2 autoescape on, and search for|safe. When converting AsciiDoc or Markdown to HTML, disable raw HTML passthrough (2-10) - For external commands, do not pass input to
subprocesswithshell=True; pass arguments as a list - Normalize uploaded filenames and path arguments, and confirm they cannot leave the directory you decided on (the
../defense) - Validate on the server. FastAPI input gets its type, length, and range from Pydantic. Validation on the Flet side does not count
- Any code that fetches a user-supplied URL limits the destination to an allow-list
- For CORS, never allow
allow_origins=["*"]together with credentials. Do not set*just to make an error go away
Third — secrets
- Never write keys, passwords, or tokens into code, into a Flet app you distribute, or into JS. Anything put into a distributed artifact can be extracted by anyone. Code that needs an external API key lives on the server
.env,*.db, backups, and exported files go in.gitignore. Before committing, check the list of what goes in- Before publishing, scan the whole history with gitleaks or the like. A key that was in the history is rotated, not erased from the history
- Check that no initial password, demo account, or sample key remains
- Do not store passwords yourself; leave them to the gate (PocketBase)
- If a distributed Flet app holds a token, keep it in the OS's secure store (the keychain). On the web, use short-lived tokens and do not leave them in the browser for long
- Base64 is not encryption. Confirm the encryption function actually exists, and that a failure does not continue in plaintext
- Never log tokens or secrets. Do not put
.envwhere the AI agent can read it (its working directory) (2-17)
Fourth — the TODOs still open
- Search for
TODO,FIXME,XXX,HACK,仮,暫定,demo,temporary,for now,skip,bypass, and for commented-out authentication or permission checks - Move what you find into the design document's "open" table: what, where, and whether it must be done before going live
- If a single item touching authentication, permissions, encryption, or input validation remains, do not go live
The checks sit between the build and production. If any one of the four fails, it does not ship.
How to check you are done
This chapter is done when these seven hold.
- Feeding the same input to the old system and to the new API produces matching output
- Days with zero diffs line up for the whole period you decided on (for a monthly job, months with zero diffs run consecutively)
- The business rules are readable as Markdown. The person on the floor reads them and says they are right
- The in-house app screens and the public web form call the same API. The same logic does not exist in two places
- The data subject to statutory retention sits complete in your own database and files
- After the old system was stopped, one monthly cycle of the business ran through on the new system alone
- The four pre-launch checks pass, and the result is recorded in the design document
diff old_output.csv new_output.csv # compare the old and new outputs
curl -s https://api.example.com/docs # FastAPI's automatic docs answer
What the human holds
Values the human supplies
- The substance of the business rules — closing dates, exception handling, the amount thresholds for approval. Fixed in Markdown
- The range of the ground-truth data — how many months of input and output to export from the old system
- The condition for ending parallel operation — how many months of zero diffs before the old is stopped
- The renewal date of the vendor product contract — counted back from, to set the day parallel operation starts
- The database connection details the new API uses, and the gate (2-05) token settings
- The values written on the one-page design rule sheet — the column count, the spacing steps, the three colors, the body font
Actions the AI states before performing
- Stopping the old system
- Switching production processing over to the new system
- Cancelling or not renewing a vendor product contract
- Writing to the production database from the new system
- Deleting data in the old system or the old database
Versions checked, and when
- FastAPI, PostgreSQL, Flet, Polars, DuckDB, Parquet — no version pinned
- The migration tool is pgloader (2-03)
- This procedure was written on 2026-07-15 and reviewed on 2026-10-06
- If a version has moved, have the AI confirm the official procedure before proceeding
Summary
"Getting along with" a core system is old.
- Parallel operation — build the new in FastAPI, run it beside the old, and compare the outputs by measurement
- Stop the old — decide the stopping condition first, and stop when the diffs vanish
- Business knowledge — push it into Markdown in one sweep. A first draft is enough; the diffs teach the rest
- The floor writes the tests — the people who know the rules write them. Outsourcing stops
- Where it lands — one API, riding on the DB of 2-03 and the gate of 2-05. The first one is the booking intake
- Screens — design is rules. Write them on one page and hand it over with every screen request
When you do it, do it. Half-hearted coexistence freezes an organization. In an era when AI has cut the cost of rewriting by an order of magnitude, there is no reason left to keep the old.
The next chapter carries the same approach used for screens out to diagrams and documents. Structure diagrams, slides, and handouts all come from text and code.
Related articles
- 2-03: Lay the Foundation — SQLite, PostgreSQL, pgvector, DuckDB, Polars
- 2-05: Stand Up the Gate — One Login with PocketBase
- 2-07: Take Documents Back — Prose in AsciiDoc, Working Tables in a Grid, Printed Pages from Templates
- 2-15: Make Your Knowledge Legible — Preparation Is the Main Body, AI the Last Move
- 2-09: Meetings and Calendars on Your Own Side — Jitsi and CalDAV