T06-L03 · Build apps · Level 3 Builder · 17-minute read, plus 3 hours of doing
The app that only works when you're in the room
Three months ago you built the group's antibody list in Base44 (T06-L02). It worked, and it grew. People now use it to ask the lab manager to reorder antibodies, and she orders from it every Tuesday and Friday. Then you go to a conference for a week. A new student signs in, sees an empty page and thinks the app is broken. Two requests for the same antibody arrive a day apart, and the group pays for two vials. The lab manager and her deputy both mark one request as ordered within the same minute. Nobody can tell which change counts, and the only person who knows how the app works is in Lisbon.
In a company it's the demo-kit list at a lab-equipment distributor. It started as a list of who has which pipette set. Now reps book kits for customer visits, and logistics ships from the bookings. Two reps book the same kit for overlapping weeks, and one customer visit goes ahead without a kit.
Neither app is badly built. Both have outgrown the builder's head. You are at Level 3 Builder: colleagues depend on this app, and when it's wrong, their work is wrong. This book gives the app what it needs to run without you: roles the data enforces, screens that explain themselves, a test copy with known answers, and a note that lets someone else take over.
After this you can
- Design two roles around what the app's table permissions can actually enforce, and test each one from its own account.
- Give every screen a clear first-use, empty, no-match, refused and error state.
- Keep a test copy of the app with made-up records whose right answers you know, and a test sheet a colleague reruns before every publish.
- Stop two people from silently overwriting each other's change on the same record.
- Write an operating note with a maintainer, a deputy and a fallback, and say where the app stops and IT takes over.
Before you start
- Books: T06-L02. You need its result: a private Base44 app under a team account, with table permissions set and a colleague's test behind it. The four-quadrant method is in T01-L01.
- Base44 on the Builder plan or higher, because this book uses Base44's separate test database. If your team can't pay for it, you can still do everything else and keep the test records in a duplicate of the app.
- Two colleagues: one who will run your test sheet without help, and one who agrees to be the deputy maintainer.
- About 3¼ hours: 17 minutes to read, about 3 hours to build and hand over, in two sessions.
Last verified 23 September 2026. Base44's test database needs the Builder plan: US$50 a month, or US$40 billed yearly. Private apps need any paid plan, from US$16 a month billed yearly. Only the Elite and Enterprise plans can restore earlier data. Details for experts at the end of this book.
The idea in one page
At Level 2 you proved the app works for one colleague on one day. At Level 3 it has to keep working for everyone, on days you're not there, after changes you haven't made yet. That takes five parts.
| Part | What it answers |
|---|---|
| 1. Roles the data enforces | Who may do what, set in the table permissions, not only by hiding buttons. |
| 2. A state for every screen | What a person sees when there's nothing yet, nothing matches, they aren't allowed, or something failed. |
| 3. A test copy with known answers | Made-up records in a separate test database, where you know in advance what every search and list must show. |
| 4. A test sheet | Ten or so lines: which account, what to do, what must happen. A colleague runs it before every publish. |
| 5. An operating note | Where the app lives, who maintains it, who deputises, what to do when it's down, and where it stops. |
Four facts shape how you build it.
- Table permissions work on whole tables. In Base44's permission settings you say who may read, create, update and delete rows of a table. They can't say "members may update the notes field but not the status field". So design the roles around tables. If two roles need to change different things, either only one role updates that table, or the thing goes into its own table.
- Your preview shows your view. You're the builder and an admin. You see every row and every button. A colleague with the User role sees something else. Test each role from its own account, in its own browser window.
- The last save wins unless you design against it. If two people open the same record and both save, the second save replaces the first, and nobody is told. For a team of eight that's rare, but it's exactly the kind of error nobody notices until the invoice arrives.
- Every prompt can change something you didn't ask for. The app builder rewrites code to make your change, and sometimes it touches a screen or a rule next to it. That's why the test sheet exists, and why it runs after every change, not once.
What stays yours: the roles, the known answers and the decision that a change is ready to publish. The builder writes screens. You decide what correct means.
Worked example: two apps, four quadrants
Both situations use the four-quadrant method from T01-L01. The first is told in full; the second shows what changes. The names, numbers and test results are illustrations.
Lab: reorder requests in the antibody list
Structure it. Aylin, the postdoc who built the antibody list, writes down what the group now expects. "Group members ask for an antibody to be reordered in the app. Petra, the lab manager, and Jonas, her deputy, order from the requests on Tuesdays and Fridays and record what they ordered. A good result: nobody orders the same antibody twice, every request shows its status, and the app runs for a week without me."
Understand it. Before prompting, she sits with Petra for twenty minutes and goes through the last month's requests, which came by email and sticky note. Three things come out. Petra sorts requests oldest first, because the oldest ones hold up experiments. About one request in ten is a duplicate of an open one. And people want to fix a typo in their request after sending it.
Her first design follows the last point: members create requests and may update their own (Creator Only on update, the rule that lets only the person who created a row change it), and Petra and Jonas update any request. Then she checks what the table can enforce. Creator Only on update lets a member change every field of their own request, including the status. A student could mark his own request as ordered, and Petra would never see it. Hiding the status dropdown from members wouldn't change that, because the permission is on the table.
Back to Structure it: "Members create requests and read all of them. Only Petra and Jonas update. A member who made a mistake creates a new request and writes 'replaces R-17' in the reason; Petra declines the old one. Before a new request is saved, the app warns if an open request for the same antibody exists." Losing the typo fix costs a little convenience. In return the status means what it says.
She writes the design down before she touches the builder. User Property Check is the permission rule that looks at a field on the person's own user record, here app_role:
| Tables | Antibodies (from T06-L02); new OrderRequests: antibody, catalogue number, supplier, quantity, reason, status |
| Status values | requested · ordered · arrived · declined |
| Roles | app_role field on the User table: member or manager |
| OrderRequests permissions | Read and Create: User Property Check app_role is member, or is manager. Update: app_role is manager. Delete: admins only |
| Screens | "New request" form with duplicate warning; "Open requests" list, oldest first; each request shows who asked and when |
| Exclusions | No prices, no supplier accounts, no emails, no connection to the purchasing system |
Choose tools. She stays in Base44. The group already knows it, the data is in it, and the two things she needs, a role field checked by the table permissions and a separate test database, are built in. The group upgrades the team account to the Builder plan for the test database. The alternative she considers is Lovable, whose built-in database runs on Postgres, a widely used database, with security rules written in SQL, its query language. Those rules can be finer than whole tables. It would also mean rebuilding and re-testing an app that works. That's a good trade only when the Base44 rules can't express what you need. Hers can.
Build it. She switches on Test Data first, so that nothing she tries touches the real list. Then she seeds the test database by hand in Dashboard → Data, with the Test switch on: six made-up antibodies and six made-up requests. Because she typed them herself, she knows the right answer to every question the app will be asked:
| Test record | Why it's there |
|---|---|
Antibodies TEST-anti-GFP and TEST-anti-GFP-HRP | A search for "gfp" must find exactly these two |
| Request R-01 (requested, 20 days old) | Must be first in the open list |
| Request R-02 (requested, anti-Actin) | A new request for anti-Actin must trigger the duplicate warning |
| Request R-03 (arrived) and R-04 (declined) | Must not appear in the open list |
| Requests R-05 and R-06 (requested, newer) | With R-01 and R-02, the open list must show exactly four, R-01 first |
She counts the open requests twice before writing that last number down. A known answer is only worth having if it's right.
Then she builds in small steps, one prompt each, and runs the relevant lines of her test sheet through the testing link after every step. That link shows her unpublished changes, working on the test data only. Her first prompt:
Add a table OrderRequests with fields: antibody (text), catalogue_number
(text), supplier (text), quantity (number, 1-20), reason (one of: running
out, new experiment, replaces earlier request), status (one of: requested,
ordered, arrived, declined; new requests always start as requested).
Add a "New request" page with a form for everything except status.
Before saving, check if an OrderRequest with the same antibody and status
"requested" or "ordered" exists. If so, show "An open request for this
antibody already exists (R-xx, requested by ... on ...). Save anyway?"
Add an "Open requests" page listing status requested or ordered, oldest
first, showing who created each request and when.
Change nothing else. No emails, no prices, no integrations.
The permissions she sets by hand, as in T06-L02: a new field app_role on the User table, then the four rules for OrderRequests. She doesn't ask the builder to do this. A rule you set and read yourself is one you can explain to the deputy.
The second prompt adds the states. The first draft of the "Open requests" page shows an empty table when nothing is open, and a raw error message when a member's save is refused. She asks for each state by name:
On every page, show a clear message instead of an empty table or a raw error:
- first visit, no records yet: explain what this page is for and show the
"New request" button
- no open requests: "Nothing to order right now."
- search with no results: "No antibodies match '<search>'." and a Clear button
- action not allowed: "Only the lab manager can change a request's status.
Ask Petra or Jonas." Show no record details in this message.
- save failed for another reason: "This wasn't saved. Check your connection
and try again. If it keeps failing, tell Aylin."
Keep every form's entries when a save fails. Change nothing else.
The third prompt deals with Petra and Jonas working at the same time. She asks for a check right before the save:
When a manager changes a request's status, reload that request first.
If its status is different from what the page showed when it was opened,
don't save. Show: "This request was changed to <status> by <name> at
<time>. Reload to see the current version." Change nothing else.
This narrows the window to a second or two, which is enough for a team of eight. A database that refuses the second save outright is the kind of thing that belongs to Level 4.
Now the test sheet. She writes it as a table in the operating note, with one line per thing that must be true. Each line names the account, the action and the result, so anyone can run it:
| # | Account | Do this | Must happen |
|---|---|---|---|
| 1 | Signed out, private window | Open the testing link | Sign-in page, no records |
| 2 | Member | Search "gfp" | Exactly TEST-anti-GFP and TEST-anti-GFP-HRP |
| 3 | Member | Search "xyz" | "No antibodies match 'xyz'" and a Clear button |
| 4 | Member | Open "Open requests" | Four requests, R-01 first; R-03 and R-04 absent |
| 5 | Member | New request for anti-Actin | Duplicate warning naming R-02 |
| 6 | Member | New request for anti-Tubulin, quantity 2 | Saved with status requested, appears last |
| 7 | Member | Try to change R-01's status | Refused, with the "Only the lab manager" message |
| 8 | Manager | Mark R-01 as ordered | Saved; R-01 still in the list as ordered |
| 9 | Manager, two windows | Open R-05 in both; mark ordered in one, declined in the other | Second save refused with the "was changed" message |
| 10 | Manager | Mark R-06 as arrived | R-06 leaves the open list |
Line 7 fails on the first run: the app shows the refusal message, but it also shows the request's catalogue number in the message text. She asks the builder to remove it, reruns lines 7 to 10, and all pass. Line 9 needs two browser windows signed in as the same manager, which surprised her colleague the first time; she adds that to the sheet. After the lines pass, she runs Base44's security scan and reads what it reports before she publishes.
Hand it over. The part that makes the app the group's is the operating note, kept next to the app in the group's shared folder:
# Antibody list and reorder requests
Link: <app link>. Private: only invited group members can sign in.
Maintainer: Aylin. Deputy: Jonas. Team account holder: the group leader.
Editor access: Aylin and Jonas, invited as collaborators.
Plan: Base44 Builder, paid by the group, renews in March.
## Roles
member: search antibodies, create requests, see all requests.
manager (Petra, Jonas): change request status.
To make someone a manager: Dashboard -> Data -> User -> app_role.
## Before you publish any change
1. Make the change in the editor.
2. Run the whole test sheet (below) through the testing link.
Every line must match. If one doesn't, don't publish.
3. Publish. Write the date and the change in CHANGES.md.
If a published change breaks something: editor -> Version History ->
restore the last good version, then tell the group.
## When the app is down
Requests go by email to Petra with "Reorder" in the subject.
Aylin or Jonas enters them into the app afterwards.
## Backups
Every Friday: export Antibodies and OrderRequests as CSV
(Dashboard -> Data -> table -> More actions -> Export) to /group/app-exports/.
Our plan can't restore old data, so these exports are the backup.
## What this app doesn't do
No prices, no personal data beyond names, no connection to purchasing.
If we need any of those, talk to IT first (see "Where it stops").
## Test sheet
<the ten lines>
Then the rerun. She gives the note to Jonas, who didn't build anything, and asks him to make one small change on his own: rename the reason "new experiment" to "new project". He makes the change, runs the test sheet through the testing link and finds that line 5 now fails, because the builder also shortened the duplicate warning. He restores the wording with a second prompt, runs the sheet again, and publishes. That's the operating note doing its job: the change that broke something never reached the group.
What it taught her: the new table took one evening. The roles, the test copy and Jonas's rerun took twice as long, and they're what let her go to the next conference without her laptop.
Company: kit bookings in the demo-kit list
Structure it. Marco, the sales rep who built the demo-kit list, writes: "Reps book a demo kit for a customer visit. Svenja in logistics ships it and marks it returned and checked. A good result: no kit is booked twice for the same days, and Svenja sees next week's shipments on Monday morning."
Understand it. He looks at the last two months. The double bookings all have the same cause: a rep books by looking at the list, and another rep books the same kit ten minutes later from his phone. His first idea is to let reps edit their own bookings to move the dates. The same table rule stops him that stopped Aylin: a rep who can update a booking can also mark it shipped. Back to Structure it: reps create and cancel bookings through a request; only logistics updates. And the app must refuse, not just warn, when the dates overlap an existing booking.
Choose tools. Same Base44 app, same Builder plan, with the sales lead's agreement. The overlap rule is the one piece he can't set in the table permissions, so he asks the builder for it as a check before saving, and makes it a known-answer line in the test sheet.
Build it. His test copy has six made-up kits and four bookings, one of them TEST-K-03, booked 12 to 20 November. His key test line reads: Rep: book TEST-K-03 for 10 to 14 November → refused, "TEST-K-03 is booked 12–20 Nov". A second line checks the edge: book TEST-K-03 for 21 to 23 November → saved. The first run fails the edge: the builder treated the 20th as overlapping the 21st. He fixes the prompt, and both lines pass. Svenja runs the whole sheet on her own the following week. Her operating note has one line Aylin's doesn't: "If the app is down, bookings go into the shared calendar 'Demo kits' and Svenja copies them in."
Where it stops. In week three the sales lead asks whether the app could create the shipping order in the company's ERP system, the central business software for orders and stock. Marco writes it into the note as the first thing that isn't his to build. Connecting to company systems, using the company's own sign-in and keeping records the company must keep is Level 4 work with IT, and T06-L04 starts there.
In both cases the builder wrote the screens in minutes. What made the apps dependable was deciding what the table can enforce, writing down right answers before testing, and watching someone else change the app without breaking it.
Where your build stops
A Base44 app with two roles, a test copy and an operating note is right for a group of up to a few dozen people with ordinary work data. Stop and talk to IT, or move to T06-L04, when any of these comes up:
- Personal or confidential data goes in: patient or participant data, HR matters, customer contacts. First ask your data protection contact (T12-L01).
- Other systems need to read or write it: purchasing, ERP, the institute's sign-in.
- Losing a day of data would cost more than a morning's work to re-enter. On most plans you can't restore earlier data, only export it.
- More than two roles or more than one team need different views of the same table.
- Nobody is left who can maintain it. A deputy is the minimum.
Stopping isn't failing. The app did its job: it showed what the team needs, and the test sheet shows IT exactly what it must do.
What goes wrong
Buttons hidden, table open. Symptom: members can't see the status dropdown, but one of them changed a status anyway, through a page the builder added later. Fix: set the rule in the table permissions, then test the refused action from a member's account, as in line 7.
Testing as yourself. Symptom: everything works for you; the first member sees an empty page. Fix: one account per role, each in its own browser window, and at least one line of the test sheet per role.
Known answers you never checked. Symptom: the test passes, but the expected result was wrong from the start. Fix: write the expected results from the records you typed, count again before the first run, and include a record that must not appear.
The sheet runs once. Symptom: a small change in April breaks the duplicate warning, and nobody notices until two vials arrive. Fix: the whole sheet before every publish, written into the operating note as a step, not a suggestion.
Real data in the test copy. Symptom: someone copies the real list into the test database "to make it realistic". Fix: test records are made up and start with TEST-. The test database is for known answers, and you only know them for records you invented.
No fallback. Symptom: the app is down on a Friday and nobody knows how to request an antibody. Fix: one line in the note and one sentence in the app's error message: where to go instead, and who enters it afterwards.
The deputy on paper. Symptom: you're away, the app breaks, and the deputy has never opened the editor. Fix: the deputy makes and publishes one real change, with the test sheet, before you call the app handed over.
Do it yourself (3 hours, two sessions)
- Structure it (15 min). Write two sentences: who depends on the app, for what, and what "working without me" means. Name the two roles.
- Understand it (25 min). Go through a month of the work with the person who depends on it most. Find the duplicates, the conflicts and the edits people want. Check each planned role against what the table permissions can enforce, and rewrite your design if they can't.
- Choose tools (10 min). Confirm Base44 still fits, or name what it can't express. Check the plan has Test Data, and agree who pays.
- Build it: test copy and sheet (40 min). Switch on Test Data. Type in six to twelve made-up records starting with
TEST-. Write a test sheet of about ten lines with known answers, at least one per role, one refused action and one conflict. - Build it: roles, states and the save check (50 min). Add the role field and set the table permissions yourself. Prompt for the screens, the states and the save check, one prompt at a time, running the matching sheet lines through the testing link after each.
- Build it: note and rerun (40 min). Write the operating note. Give it to your deputy. Watch them make one small change, run the whole sheet and publish, without your help. Fix the note wherever they got stuck.
Exit check
Delivered artifact: a published Base44 app and its operating note, with:
- two roles set in a User field and enforced in the table permissions;
- a test database with made-up
TEST-records; - a test sheet of about ten lines with known answers, covering each role, one refused action, one empty state and one conflict;
- the operating note: link, maintainer, deputy, account holder, publish steps, fallback, weekly export, and where the app stops;
- the rerun: the date your deputy ran the sheet and published a change.
It passes when a colleague who didn't build the app runs the whole test sheet through the testing link and every line matches, and the deputy has published one small change without your help.
Rule to remember
An app is the team's when someone else can change it, test it and publish it without you.
Details for experts
Checked on 23 September 2026. You don't need this to follow the book; it's for setting things up or answering a colleague.
| What | Details | What it means for you |
|---|---|---|
| Base44 plans | Paid plans start with Starter at US$16 a month billed yearly; yearly billing saves 20%. Builder costs US$50 a month, or US$40 billed yearly. | Budget for Builder if you want the separate test database. |
| Private visibility | Needs a paid plan. Set it under Dashboard → Overview → App Visibility. | Private means only invited people can sign in. Set it before you invite anyone. |
| Invited people | Get the role Admin or User. Neither can open the editor or the dashboard. | Your deputy must also be invited as a collaborator, or they can't change the app. |
| Table permissions | Dashboard → Data → (table) → Permissions → Edit. Four rule types: All Users (everyone signed in), Creator Only, Entity-User Field Comparison (a field in the row must match the signed-in person) and User Property Check. | Matching any one rule gives access, so a loose rule opens the table whatever the stricter ones say. Rules cover whole tables, not single fields. |
| Role field | You can add your own field, such as a role, to the User table and check it with User Property Check. | This is how app_role in the example works. |
| Test Data | Builder plan and higher: Dashboard → Settings → Advanced Capabilities → Test Data creates a new, empty test database. The published app always uses the real data. | Fill it by hand with TEST- records. They never mix with the real list. |
| Testing link | Publish → Testing link shares your unpublished changes with the test data only. | Send this link to whoever runs the test sheet. |
| Version History | In the editor, it restores earlier versions of the app's code and design. Restoring earlier data is only on Elite (7 days back) and Enterprise (30 days). | On other plans, the weekly export in the operating note is your only backup. More in T06-L04. |
| Security scan | Runs from the Security tab. | Run it before you publish and read what it reports. |
Further reading and tools
Next books
- T06-L02 · Build a Small Shared Tool From a Prompt, and Test It With a Colleague: the private app and table permissions this book builds on.
- T06-L04 · Put Your Team App on the Organisation's Own Database, and Prove You Can Restore It: your organisation's own database and API, backups and a real restore.
- T12-L03 · Give an Unattended Workflow Limits and a Stop a Colleague Can Use: who is responsible when the app runs on its own.
- T16-L03 · Test a Tool on Your Own Work Before Your Team Depends on It: checking a platform before a group depends on it.
- T17-L03 · Explore What Already Exists Before You Build: whether the institute already runs something that does this.
Tools
- Base44: Taught. Roles, table permissions, Test Data, testing link and Version History.
- Lovable: Catalogued. The alternative when you need rules finer than whole tables.
- v0, Bolt.new: Catalogued. Other prompt-to-app builders.
- Supabase: Catalogued. The open-source database platform, run on your organisation's own server, that T06-L04 teaches.