← PWE Studio home 中文

Customer resources

Release evidence

A customer-readable record of what this release changes, what the production deployment established, and which commitments remain deferred.

Released v10.20.0 · package, production deployment, and browser acceptance verified

Since v8.1.0

Everything below belongs to a released product version. Each line is delivery evidence, not a roadmap promise.

Read entries chronologically: an older entry describes the boundary of that release and does not override the latest one. The current integration boundary is Xero Beta with gated one-way transport, not the earlier Preview-only state.

v10.20.0 — a quieter back office: one primary action per page, each number said once

The back office is quieter and says each number once. On a student's card the three actions are now ranked — open the record leads, top-up and scheduling sit under it — instead of twelve equally urgent buttons down the page; the check-in list keeps its per-row button, because pressing one as each person arrives is the job, and the batch check-in that supersedes it no longer shouts over them. The 「待上课」 tag now appears only when a row is NOT in the ordinary state, so checking someone in visibly changes their row and a low balance is the only mark in the list. Today's headcount used to be printed three times on the dashboard and the total student count twice; each is stated once now, and the roster's list header no longer repeats the date sitting directly above it. Nothing below 11px anywhere in the back office. The credit badge tells a screen reader what it counts. The sidebar's green "connected" light is gone — it was not wired to anything and said connected while disconnected; the one in the top bar is real and stays. In the platform console the tenant table no longer prints a subscription status identical to the pill above it. And on a phone, the customer release-notes page no longer scrolls sideways. No data changes; nothing to do on your side.

v10.19.0 — a real error page, one contact address, and an enquiry form that reaches somebody

Wrong addresses now get a page instead of a line of JSON — in your language, saying what a studio's public address looks like and how to get back. Every contact address on the privacy policy, terms and support policy is now info@pwestudio.site, and the enquiry form on the product site actually addresses it: both of its buttons used to open an empty composer, and a long message in Chinese silently opened nothing at all. Studio websites are now readable even if their page script fails — before this, one error left almost the whole page invisible. Accessibility across the product: the manual's numbered steps and search highlight, twenty status labels and six hover states in the two consoles, three missing focus outlines, and the secondary button's edge all now meet the contrast standard for text and controls; the CMS's "connecting" spinner works again for people who ask their device for less motion, and every frosted-glass surface now has a solid fallback for Reduce Transparency. On the product site the main button is now ink rather than amber, amber is kept for one closing band, and the recommended plan finally carries the primary action. Prices on the pricing page come from the plan table only. No data changes; nothing to do on your side.

v10.18.0 — the product moves to /studio and the house takes the front door

PWE Studio is now one product line of PWE · 天域, and the company's own website is taking over the root of pwestudio.online. The product home lives at /studio (Chinese: /zh/studio/); its canonical address, language links, sitemap and llms.txt all say so, and the product's llms.txt is also served at /studio/llms.txt. Nothing you bookmarked breaks: studio websites, registration, the CMS, Studio Admin, pricing, the manual and the customer documents keep their addresses. Studio website addresses under the company site's sections (production, work, tools, labs, about, services, contact, ai) and under the product's own pages (studio, pricing, manual, …) can no longer be created, so a new studio cannot be given an address that would never be reachable. If you added the staff CMS or a student portal to a phone's home screen, it now opens on the console or the product home rather than on the company website; installed apps refresh this on their next visit. Footers on studio websites and in the CMS read Powered by PWE. Text only — no logo, icon or image changed in this release.

v10.17.0 — the last page that compiled CSS in your browser, and a report that draws its icons

The student registration page used to download a 451KB stylesheet compiler and run it in the visitor's browser before showing anything; it now ships a 17KB stylesheet built ahead of time, and looks pixel-for-pixel the same — verified across 166 elements and 21 computed properties. The growth report you send a parent draws its five icons at last (they were markup the browser rendered as nothing, and which swallowed the button labels beside them), and it is now written in one language throughout: four lines that should have followed the report's language never did, so an English studio's report arrived with Chinese buttons. Status labels in the sidebar and the course help card were being tinted toward the wrong end of the page and sat at 2.75:1 contrast; they are 8.50:1 now.

v10.16.0 — two audits, cross-checked, and the one thing neither found

Booking a make-up lesson used to spend the family's credit, put no lesson on any timetable, and report success. It is now one transaction: no lesson, no charge. Marking a lead as contacted no longer wipes the follow-up date you set; 待处理 is a queue you can filter by what is due today. "View invoice" opens the invoice instead of an empty ledger. Studio Admin is editable on a phone again. The CMS shows an explanation instead of a blank page when something goes wrong, and an expired session no longer discards what you were typing. Monthly business figures are computed over your whole history rather than the last 500 records. The console follows your browser's language on first use, money and irreversible actions are translated, and the CMS no longer downloads a 451KB stylesheet compiler before it starts.

v10.15.0 — the console stops stacking, and the public page gets material

Four separate amber reminders on the dashboard became one 需要注意 section and the 722px activity block became a single link: the landing page lost 43% of its desktop height and 46% on a phone. Class Schedule split into 今日签到 and 排课设置, which takes a teacher from 55 visible buttons to 26, and gained a full-month view. On a 375px phone all seven settings sections are now reachable. The public page gained paper grain under its dark band, a category watermark on course cards, and a reading line across the top. (Written up at the v10.16.0 release; the entry was left as a skeleton at the time.)

v10.14.0 — the product home becomes one connected studio story

The PWE Studio product home has been rebuilt around the Living Studio System: Portal, Quick Registration, Operations CMS and Studio Admin now appear as four connected surfaces around one studio core. The page remains semantic HTML first, with light and dark static posters, a Canvas fallback, and a self-hosted Three.js scene on capable desktop browsers. Mobile, reduced-motion, data-saver and WebGL-failure paths keep the complete content and every ordinary link.

v10.13.0 — front desk can check people in; Staff became Assistant; the roster shows you the register first

Front desk can now check a student in and deduct the credit. It could already top up and adjust a balance directly; refund authority remains with Owner and Manager. Withholding check-in only pushed the counter towards editing numbers by hand, which is harder to audit than an attendance-linked deduction. Separately, the "Staff" role is now "Assistant" and is a strict subset of Teacher: everything an assistant can do, a teacher can do. It previously held more than a teacher — student records, credit balances, registration approvals, billing. If you assigned someone Staff expecting them to edit student records or adjust credits, move them to Manager or Front Desk as appropriate. On the Class Schedule page the day's register now sits directly under the date and the day summary; adding students, group templates, one-to-one lessons and the weekly timetable all moved below it. On a desktop the first five students are now visible without scrolling — previously none were. Two authorisation boundaries were tightened in the same release. The leave policy inside Recurring private lessons — which decides whether a late-cancelled lesson still pays the teacher, and whether a family is still billed when the studio closes — now needs Owner or Manager. It used to share one key with ordinary scheduling, which the front desk holds; no page the front desk could open reached that form until this release gave it the Class Schedule page, so the split was made before shipping it. And the list of waiting booking enquiries, with each family's name and phone number, now needs the same permission as deciding on them; it previously needed only a sign-in, so teachers and assistants received it. Also fixed: a hand-edited credit balance now shows who edited it in the activity log — the ledger recorded it, the log never displayed it; the copied daily report now names the date you actually selected; "save today as a template" no longer drops students who came from the weekly timetable; "convert to weekly class" now opens and scrolls to the editor instead of appearing to do nothing; the phone's day-actions menu closes after you choose something; editing a credit balance by hand is now recorded against you, the same as a check-in already was; and the dashboard's birthday reminder no longer skips the week that crosses New Year.

v10.12.3 — fixed: Studio CMS sign-in, and the parent booking form

An internal code reorganisation in v10.11.0 changed how one module was referenced, and two paths stopped working. Signing in to the Studio CMS returned "not found" for every studio — browsers holding a live session were unaffected, so this only appeared when somebody needed to sign in again. And submitting the booking form on the public timetable returned a server error. Both are fixed. The sign-in box also used to show the internal error code rather than a readable sentence. Automated checks now cover both paths so a change of this kind cannot pass silently again.

v10.12.2 — a sample studio that recorded a settlement can be reset again

Once a sample demonstration studio had actually recorded a settlement — credits attached to a payment on the top-up screen — resetting it failed and rolled back, and kept failing every time after that. The reset was missing two tables that hold references to payment records. Both are cleared now. This affects sample demonstration studios only; no real studio's data is involved.

v10.12.1 — check-in stops charging quietly, and the sample studios stop sharing an identity

Three corrections on the path that spends a student's credits. The batch confirmation used to say "today" while acting on whatever date was selected, so a term's worth of credits could be charged against next Wednesday without the date ever appearing on screen; it now names the date it will charge. Checking a student in for a lesson that has not happened yet now asks first, and dates outside the permitted range disable the button and say why. And whether somebody was already checked in was read from a rolling window of recent activity — for a busy studio, check-ins from more than about six weeks ago fell out of that window, showed as "expected", and a second press of batch check-in charged a second credit. It reads that day's attendance directly now. Batch failures also say why they failed rather than only who. Separately: the birthday message on the dashboard, including the text of the one-tap SMS, used wording written for a painting studio; it now comes from your own message templates. Billing details are maintained by the Owner — a manager previously saw an editable form whose save was always refused, and now sees a read-only view.

v10.12.0 — a music studio sample, and demonstration resets that know which studio they are on

There is now a second sample studio: Zhiyin Music in Glen Waverley, Melbourne, teaching piano, violin and voice alongside guzheng, erhu and pipa. It carries twelve students, nine courses, a published timetable, a term's billing and end-of-term reports — all invented, all synthetic — so a music school can be shown a music school rather than a painting studio. Underneath, the sample generator no longer knows what industry it is building: room names, payers, invoice lines and report wording belong to an industry pack, and adding an industry is adding a content file. The painting sample's output did not move a byte. Two corrections came with it: the Platform Admin "reset demonstration tenant" button rebuilt the painting studio no matter which tenant it was pressed on, while the audit record named the one that was pressed — the tenant now decides, a tenant no pack owns is refused, and each confirmation phrase names its own studio; and the two samples had been writing their handover credentials to the same file, where whichever reset ran last overwrote the other.

v10.11.1 — the demo pages stop claiming a nightly reset, the integration is marked Beta

Four public demo pages carried a footer saying the data resets nightly. No such timer ever existed — the demonstration tenant has always been reset by hand, deliberately, because whether the sample data should return to baseline depends on what the previous demo did. The wording now says what actually happens. The Xero integration page is marked Beta while one full settlement month is proven against a real ledger, and says so in words a studio owner can act on. Two bilingual field labels that rendered differently on their Chinese and English halves are aligned. Operationally: the console browser smoke check now runs inside the release gate rather than by hand, the database backup password no longer travels on a command line where the host process list could show it, and the live nginx configuration — including one site snippet the repository had no record of — is now version-controlled.

v10.11.0 — a structural refactor: monoliths split, duplicates merged, behaviour unchanged

A maintainability round with zero user-visible change, verified by machine: the 15,926-line backend API file became a package of 13 domain modules (all 191 routes compared identical before and after); the CMS front-end gained seven panel files verified screen-by-screen against the 48-shot screenshot pipeline; the three surfaces now share ONE translation engine (dictionaries stay separate, and a new gate fails the build on duplicate dictionary keys — its first run caught and cleaned 52); the two password-hash implementations became one that still verifies every historical format; and both consoles’ ~4,200-line inline scripts moved to versioned assets guarded by a new real-browser smoke check — which caught, on its first run, a real defect where a failed Studio Admin login showed only a 3-second toast. Fixed.

v10.10.3 — the number-collision guard: never overwrite someone else’s document

Connecting the first real ledger surfaced a sharp edge: Xero’s create endpoints upsert by document number, so pushing an INV-0001 into an organisation that already holds one UPDATES the existing — possibly paid — invoice. The create path now probes the target organisation by number first; a number that exists and is not this studio’s own push dead-letters immediately with an actionable reason (a distinct number prefix, or a dedicated organisation). Nothing is ever silently rewritten.

v10.10.2 — connecting picks the organisation you just consented to

One Xero user can authorise different organisations for different studios (a demo ledger and a real one). The callback used to take the first row of /connections — always right with one org, order-dependent with several. It now matches the exact consent event (the access token's authentication_event_id against each connection's authEventId): the org whose Allow you clicked is the org that connects. If no match exists it falls back to the newest connection — the most recent human decision — never silently the first row.

v10.10.1 — the "enable pushing" switch clears its own gate

Live acceptance of v10.10.0 reached the final wizard step and found the enable-switch upsert always tripped the database gate: PostgreSQL checks constraints on the INSERT candidate row (push on, preconditions empty) even when the update branch would run. Unreachable while the transport was off; the first real walk exposed it. Enabling is now a plain UPDATE of the row whose preconditions the gate just verified. A regression test walks the whole wizard against the real constraint.

v10.10.0 — Xero one-way push (X3): queue, reconciliation, wizard

Issued invoices, credit notes and recorded payments now queue into the studio's own Xero organisation — amounts pushed in our exact cents (Xero never re-derives the tax), under local document numbers, with payments split per invoice allocation. Pushing stays off until the wizard is walked: connect, accountant-confirmed account mapping, a real trial run against the Demo Company (push everything, read everything back, zero difference required), and the single-entry question. Strictly one-way: nothing is read back or edited from Xero.

Failed pushes are listed with Xero's own reason and replay under the same idempotency key — a retry can never create a second document. Rate limits and outages back off automatically; the queue drains every five minutes on the server, or on demand from the integrations page, which also offers per-document reconciliation.

v10.9.4 — the first successful Xero connection: scopes finalised

The v10.9.3 scope set was still refused at Xero's consent page. Live bisection located the two offenders — app.connections and accounting.settings.read appear in the app's own configuration list but the authorize endpoint refuses them for this app class. The final set (invoices, payments, contacts, identity, offline access) reaches consent, connects, and covers the whole later document-push surface in one grant.

Accepted live against the Xero Demo Company (AU): connect, cancel branch, and token self-heal all verified; the organisation name on the connected card is fetched without app.connections, proving that scope was never needed.

v10.9.3 — Xero authorisation on the new scope scheme, and interface-language purity

Xero apps created after March 2026 only accept the new granular scopes — the old broad scope was refused at the consent page before it ever appeared. The connection flow now requests the minimal granular set (invoices, payments, contacts, read-only settings, connections), granted once so the later document-push stage will not ask every studio to reconsent. The connection still pushes no accounting data.

Interface: the English CMS and both admin consoles fix the same three defect families — phrases now render as whole sentences (no more fragments like "(12 )"), duplicate dictionary keys no longer overwrite each other, and placeholders/tooltips stay translated instead of only on first load. The registration field-type picker shows labels again. Plan student limits are aligned across environments, and the online manual's 48 screenshots were re-taken on a single v10.9.2 baseline.

The invoicing chapter's pictures match the product again (v10.9.2)

One screenshot in the manual's invoicing chapter had been captured mid-animation — the settings page frozen halfway across the screen. All four of the chapter's screenshots were re-taken, and the capture tooling now waits for the page to stop moving before it looks, so this class of picture cannot ship again.

One caption also overstated who can edit your invoice identity: a manager can read it, but saving it belongs to the owner alone. The manual now says exactly that.

v10.9.1 — Xero environment passthrough fix

The v10.9.0 integrations page reported "unconfigured" even with credentials correctly written on the server: the container environment block is an allow-list and the four XERO variables were not forwarded. This release adds only that passthrough.

v10.9.0 — Xero connection (X2)

A studio can now connect its own Xero organisation from Settings → Integrations: OAuth2 authorization-code with PKCE, tokens encrypted at rest on the server, silent access-token renewal, an honest "expired — reconnect" state when the refresh token dies, and a disconnect that revokes at Xero and wipes local tokens. The connection pushes no accounting data — document push stays behind the next stage's gate. Try it against the Xero Demo Company first.

v10.8.0 — billing workbench, student timeline, brand & navigation repairs

Money: a read-only student timeline merges enrolment, credits, invoices, payments, credit notes and progress reports into one stream; payers gain a printable monthly statement; invoices can record a chase reminder (history only — nothing is sent); the dashboard shows receivables and one-tap renewal for low-credit students; approval offers an explicit merge-or-create choice when a registration looks like an existing student; and issuing now checks the invoice profile (name, address, ABN) before a document can leave the studio. Printing outputs exactly the selected document — invoice, credit note and statement no longer print on top of each other.

Surfaces: the public-page brand lockup is now one rule everywhere (logo present → logo only; no logo → the full studio name), language switching re-measures the navigation so wide screens no longer ellipsise every link, anchor links land correctly on cold load, and both the CMS and Studio Admin now explain permission denials instead of showing a misleading connection error. The tenant privacy note is expanded to a ten-section version aligned with the Australian Privacy Principles. Xero remains Preview-only.

Invoice print correctness and v10.7.1 repair release

This release closes the v10.7.0 repair checklist around explicit credit-refund sources, stable tax-rate snapshots, payer review, aggregate invoice drafts, accounting exports, and customer-document printing. The browser print fallback now isolates the issued snapshot document from the CMS shell and names the generated PDF header for the selected invoice, such as Tax Invoice · INV-0007. Xero remains Preview-only.

The release is committed, checksum-verified in SaaS and Edition archives, deployed to production, and accepted on the public routes. The latest handoff keeps the exact runtime commit, archive hashes, backups, and deep-health evidence separate from this customer summary.

Invoice operations and explicit credit settlement (v10.7.0)

The candidate unifies mobile timetable overflow fixes, payer selection, immutable issued-document snapshots, one InvoiceDocument contract, audited CSV exports, and truthful print/save-as-PDF fallback when a portable PDF renderer is not available. It adds one atomic, idempotent path for a credit top-up to create an invoice and optional payment, plus an explicit-source refund path that issues a credit note, records the payment refund, and leaves a tenant-scoped bridge between the two ledgers.

Released from commit 913c6f1. The SaaS and Edition archives passed checksum, BUILD_INFO, entrypoint and exclusion gates; pwestudio.online reports v10.7.0 with the new migration applied and stored themes readable. Xero OAuth and transport remain a later Preview/Beta project.

Source candidate: money contracts and honest boundaries (v10.6.4)

This is a source candidate prepared from v10.6.3. It has not been committed, packaged, pushed, or deployed; the verified packages and production runtime remain v10.6.3.

The candidate locks invoice allocation to the selected account and invoice, records payment and refund amounts, balances, and the acting user, rejects unsupported money fields, and describes Xero as Preview until real transport exists. It also adds clean-checkout and archive smoke gates. No migration was added or applied.

Clearer screens, and a report worth sending (v10.6.3)

Form fields now have a visible edge — the outline was so faint it was easy to miss where a box began — and tapping one on a phone no longer zooms the page. On an iPad the save bar no longer sits on top of the last row of theme cards.

In a student's portfolio, colour now means something. The consent panel used to sit under a green header even when no consent had been recorded; it now shows the state it is actually in. Buttons that do the same kind of job look the same.

The growth report you send home no longer prints browser text in its header, fits on one page, and starts its attendance chart at the month the student joined rather than several empty months earlier. The auto-written teacher's note is gone: if a teacher has not written one, the report simply does not have that section, which is more honest than a paragraph that repeats the numbers above it.

Works, activity log and student records gain the same filter bar the billing screens already had: one search box, categories with counts, a result count that is always visible, and one button that clears everything.

Your website's menu, back on screen (v10.5.0)

On a desktop your studio site was folding its whole menu into a single ☰ button, on every screen size — even a very large one. Four of the menu entries also did nothing when clicked. Both are fixed: the menu now opens across the top on a normal desktop, and every entry goes where it says.

If you filled in your own page title for search engines, it was being stored in a form that showed up as programming text in the browser tab, in Google's results and in link previews when someone shared your site. Studios that had left the field blank were never affected. The title is stored correctly now, and pages saved earlier display correctly too.

Pages also load faster: the largest files were being sent uncompressed, which we have corrected. A first visit to the operations console now transfers about a third of what it did.

Your studio's data, separated by the database itself (v10.3.1)

Every studio's records have always been kept apart, and we check that on every release. Until now that separation was enforced by the application asking the right question each time. It now sits in the database: a query that failed to say which studio it was for returns nothing at all, rather than depending on us never writing one.

The application also stopped connecting to the database with administrator rights. It can now read and write your records and nothing else — it cannot alter the shape of the database or empty a table. Neither change is visible in the product; both narrow what could go wrong.

Settings page layout fix (v10.2.2)

The settings screen in v10.2.0 drew itself beside the content area instead of inside it, so the page looked broken. Fixed within the day. Nothing you had saved was affected — it was where the screen was drawn, not what it held.

Filters where the lists were (v10.2.0)

Billing and teacher pay now carry the same filter bar: a date range with this-month and last-month presets, a search box, and state chips that show their own counts — so "Overdue 2" tells you whether it is worth clicking before you click. What you filter to goes into the address bar, which means the overdue ones can be sent to a colleague and last month's pay run can be sent to your accountant. Both were spoken instructions until now.

System settings became an ordinary page instead of a panel that covered everything, so the sidebar stays put and there is no longer a "back to dashboard" button to press. Its sections are proper tabs now: one at a time, and your browser's back button moves between them.

Your own details on the invoice (v10.1.1)

An Australian tax invoice has to carry the ABN of the business issuing it — without it the family's accountant cannot claim the GST. There was nowhere to record yours, so Settings now has an Invoice details section: legal entity, trading name, ABN, whether you are registered for GST, your address and how you would like to be paid. Until it is filled in, invoices will not issue; and if an invoice charges GST while your ABN is missing, we refuse it rather than send a document your customer has to ask you to redo.

The billing screen also gained a New invoice button — pick the payer, enter the lines, save as a draft. Issuing stays a separate press, because that is the moment the number is allocated and the figures stop being editable.

The money layer, on screen — and the private lesson (v10.1.0)

Everything described in the entry below was built in v10.0.0 and reachable only through the interface your developer uses. It now has screens. Billing shows who owes what and lets you issue and record against it; Finance shows what teaching cost and what it billed; Xero is a Preview-only preparation screen. Its mapping and gate state are visible, but there is no provider transport and no data is sent to Xero.

Progress reports are written where the child's record is, next to the attendance and lesson notes the report was assembled from — and the ones that are overdue now appear in the same place you already look for work waiting on someone. Writing a report and knowing whose reports are late are different questions, so they get different screens.

And the one-to-one lesson is now a first-class thing rather than a class with one seat. Set it once and it repeats weekly, skipping your holidays and any weeks you pause. When a lesson does not happen, recording it answers three separate questions — is the family still charged, is the teacher still paid, and is a make-up owed — because those genuinely have different answers. A student cancelling an hour before is normally charged and the teacher normally paid; a studio closing for a public holiday charges nobody and pays everybody. You set the rule once, in plain words, and the system applies it and shows you what it decided.

Invoices, payments and teacher pay (v10.0.0)

Until now the system kept a careful account of lessons and none at all of money. It can now invoice the person who pays — a family with three children is one invoice, a school booking a workshop is one payer with no students attached — record what arrives against it, and tell you at any moment what each family owes and how long it has been owing.

An invoice you have issued can no longer be edited, by anyone, including us. That is deliberate: a document a family and an accountant have both seen has to stay the document they saw. Corrections happen the way they do on paper, with a credit note that reverses the charge and leaves both records standing.

Xero is currently a Preview boundary, not a live connection. The product keeps account and tax mapping, gate state, idempotency keys and queue/replay structures ready for future work, but there is no OAuth or provider transport in this release and no invoices or receipts are sent. Any live accounting integration needs separate implementation and acceptance.

Teachers can see their own hours and what they add up to, and confirm them at the end of a period. Nobody else's hours, and no view of what families owe. We work out the amount and produce the list; paying it stays with whoever runs your payroll, because tax withholding and superannuation belong to your accountant and not to your scheduling software.

Families can subscribe to their child's lessons once and have them appear in their own phone calendar from then on, rescheduled lessons included. This is free and it replaces the reminder message you would otherwise pay for every week. It does not replace a same-day cancellation: phone calendars refresh on their own schedule, so those still go by text.

And the progress report you promise parents can now be assembled from what has been recorded all along — attendance, lesson notes, repertoire, exam progress — for a teacher to finish and publish. Nothing reaches a family that a teacher has not read first.

The manual caught up with the product (v9.9.6)

The online manual said your web address could never be changed. It can, since v9.9.0 — so the manual now says the true thing, and its questions section answers it directly: ask us, the old address redirects forever, and it is never given to another studio.

Every screenshot in the manual was taken again against this release. Some were two versions old, which meant a reader comparing their own screen with the picture could reasonably conclude something was wrong with their studio. The Selected Work page — which has had an address of its own since v9.8.10 — now appears in the manual as its own picture rather than only as a paragraph.

Two corrections to v9.9.0 (v9.9.5)

The switch for Selected work said you had published nothing while your website was showing your pieces. The editor was asking the wrong question of its own records; the site was right all along, and the counter above the upload area was right too — which is how one screen managed to disagree with itself.

A long navigation label was being shortened twice, once by the server and again by the browser, which left an ellipsis inside an ellipsis and a call-to-action button pressed against its own border. The server now decides alone, and the button — which has the least room and the most padding — is allowed less than the other entries.

Navigation that stays put, a name that follows you, and an address you can change (v9.9.0)

Clicking an entry in your site's navigation used to reload the whole page whenever the visitor arrived with anything after the address — a language choice, or the tracking tag on an advertisement. It scrolled instead of reloading now, and the visitor's language and the advertisement they came from both survive the click.

Your four public pages now offer the same entries. Questions & Answers used to appear only in the home page's footer, and the timetable page linked to itself in a way the switch could not turn off.

Renaming your studio now reaches the places a machine reads: the browser tab, the card that appears when someone shares your link in WeChat or WhatsApp, and the name search engines show. Until now those kept whatever the studio was called on the day it was created, even though the page itself looked correct.

Studio Admin says one thing one way. Every section switch reads Show X on the website, and Publish now belongs only to the button that puts your draft online; a switch labelled Publish that merely saved a draft was a fair thing to misread. All nine switches are in one list, each saying why a section you have turned on is not public yet — no student has agreed to show their work yet rather than a code. The principal has a panel of its own.

A studio can now change its public web address. The old address keeps working forever and redirects to the new one, so printed QR codes and flyers do not need reprinting; students, courses, work and schedules are untouched. Ask us to make the change — it is done once a year, from the platform side.

The Chinese console is Chinese. Sixty-eight strings had no translation, including the sentence shown when a publish is still being confirmed.

A server-authoritative public shell and honest publish status (v9.8.10)

Studio Admin now reads publication status from the server ledger instead of comparing a browser snapshot of websiteProfile. A successful write remains separate from a pending public projection, and structured bilingual status codes explain whether to retry, complete content, or wait for verification.

The portal, standalone showcase, timetable and registration page share a versioned public-surface contract with localized labels and common navigation, footer and CTA actions. Public footer links to staff CMS and Studio Admin are removed; operator tools stay behind authenticated entry points.

This release keeps the existing Vanilla HTML/CSS runtime and tenant data model. It is ready for package and production verification; the exact source, package and production evidence is recorded separately in the latest handoff.

A truthful Studio Admin editor and one public-surface contract (v9.8.9)

The preview now separates Draft from the real Live website, lists unpublished change groups and public readiness, and keeps publish errors visible with a route back to the field that needs attention. The Hero secondary action can target courses, selected work, timetable, registration or a validated external URL; a chosen destination that is not ready stays hidden instead of silently redirecting elsewhere.

Space & Experience is a dedicated editor for the place, atmosphere, process or online experience. It preserves six highlights, supports six ordered photos with bilingual alternative text, and uses visitor-controlled thumbnails without autoplay. The portal, showcase, timetable and registration page consume the same server-authoritative module, navigation, footer and action contract.

Truthful public navigation and safe publish verification (v9.8.8)

Studio Admin now separates a successful write from the follow-up public check. If the content is saved but a projection is still catching up, the console keeps a clean editor, shows Published, public pages still need verification, and offers a retry instead of reporting a false failure. Errors use structured codes with bilingual operator copy.

The portal, standalone showcase, timetable and register page share one public-surface contract. Navigation and footer entries require both owner intent and real published content, while the preview explains unavailable entries and the next action. The bright workbench rail uses an information tint for selection and keeps the 1.618 editor/preview split.

Released to pwestudio.online from commit 4b436e1e2df0717b7efb01d5e7d4021a6cc23860. The SaaS and Edition package SHA-256 values are 1d6fc1760993864c681c8f9cb5e58eac303acdb65573ba98978181f226ee3da7 and 0a75bf66059da97dc91b450933bd2a44e48200b7dda17030b62baa22ec1cd3b6. Deep health is v9.8.8 with db=ok, six readable tenants and themes.unreadable=0; the database dump and volume archive were created before the switch, and v9.8.7 remains available for rollback.

A ranked, shareable studio showcase with a lighter home page (v9.8.7)

Studio Admin now supports an optional tenant-wide Featured rank. Lower numbers lead the home preview (six works); blank ranks keep the existing order. The full archive lives at /<slug>/showcase, preserves the same ranking, supports category URLs, and loads twelve eligible works per page with automatic pagination plus a Load more fallback.

Plan changes remain content-safe: the rank and all stored works survive upgrades and downgrades; the plan only controls how many Active works are public. Public pages, timetable, registration and footer navigation now share the same cross-surface entry points.

Released to pwestudio.online from 4e1894f. Production deep health is appVersion=9.8.7, db=ok, six readable tenants and no unreadable themes; the 0030_showcase_featured_rank.sql migration and pre-switch backups completed successfully.

A clearer online manual for the public timetable and booking flow (v9.8.6)

The bilingual manual now gives the public timetable its own chapter at /<slug>/timetable. It explains the two switches required to publish a class, the 1–4 week display and booking window, field visibility, teacher-name consent, and why a booking request is not a seat.

Four paired screenshots show the Studio Admin settings and the mobile request dialog. The captures use the synthetic showcase tenant and do not write to customer data.

Action context and plan-aware studio editing (v9.8.5)

The Platform Admin Actions column now opens an anchored menu for frequent tenant and plan commands. Row clicks remain quick views; the right panel explains the selected operation and waits for an explicit confirmation step.

Studio editing adds section navigation and a save review for changed entitlements, preserved website/brand/showcase content, tenant notifications and over-limit published works. The API exposes active, draft and archived showcase counts for the same review.

Released to pwestudio.online from commit bcd4f1b. The SaaS and Edition packages passed checksum and bundle verification; production deep health is v9.8.5 with db=ok, six tenants and no unreadable themes. The latest handoff records the backup, migration, immutable asset, media ETag and public-route evidence.

Plan changes with preserved studio content and clearer Platform Admin actions (v9.8.4)

Plan upgrades and downgrades now show a review of changed limits, preserved content, current usage above a lower limit, and tenants to notify. The operator must acknowledge the review, and the API applies the same two-part guard before accepting the change.

Tenant and plan rows open quick views directly; editing, support, lifecycle and deletion actions are grouped under the center Actions control. Website, brand, showcase, student, course, registration, media and audit data stays preserved across a plan change.

Plan-linked showcase publishing with safe work states (v9.8.3)

The public showcase now follows the plan entitlements: starter publishes 15 active works, studio 60, and growth 150. The 12-item page size is pagination, not the plan limit.

Each work can be Active, Draft or Archived. Downgrades keep every stored work; new uploads beyond the active capacity become Draft instead of being rejected or deleted. Super Admin plan edits now preserve an existing showcase limit when the field is omitted.

Plan-safe studio content and a contained showcase viewer (v9.8.2)

Changing a studio's subscription plan in Platform Admin now preserves its tenant-authored website, principal, hero, FAQ and showcase settings. The update locks the tenant row and carries omitted nested settings forward instead of replacing them with defaults.

The public showcase lightbox now keeps every portrait or landscape image centered inside the available viewport, with the title, caption and navigation remaining separate and usable on desktop and mobile.

A full-width Platform Admin workbench with real center editing (v9.8.1)

The Platform Admin shell now uses the available canvas more deliberately: the left rail locates work areas, the center owns the active workflow, and the Inspector keeps status, impact and safe next steps visible. Tenant and plan editing now opens in the center workspace with an always-available save bar instead of a centered modal.

View is the default list action; edit and danger actions stay in the selected context. Phones use a discoverable work-area drawer, the page has no document-level horizontal overflow, and new status, attention and editor copy remains bilingual. No online payments, bank-transfer settings, Gmail/SMTP, AWS SES, SSE, WebSocket or browser push are added.

Candidate scope is recorded here; the final production commit, package hashes and public acceptance remain in the latest handoff after deployment.

A three-column Platform Admin workbench for focused operations (v9.8.0)

Platform Admin now uses a clear workbench relationship: the left rail finds a supported area, the center performs the workflow, and the right Inspector holds the selected tenant, plan, or audit event. Today opens with a Needs attention queue based on current tenant, subscription and usage data.

The rail exposes only current capabilities — Today, Tenants, Plans & Pricing, and Audit Logs. The Inspector follows status, risk, subscription/resource information and safe actions; Support Mode stays separate and requires a reason before the existing audited flow starts. Mobile uses a responsive Inspector sheet without horizontal overflow.

This release does not add online payments, bank-transfer configuration, Gmail/SMTP, AWS SES, SMS, SSE, WebSocket or browser push, and does not expose future placeholder pages.

Production acceptance: v9.8.0 is running at pwestudio.online from commit 906d18549475ac35b2cabd24c31a7944b83cfc31. Deep health reports appVersion=9.8.0 and db=ok; critical routes, the immutable Platform Admin asset hash/cache response and the production login boundary were verified.

The exact source, package and production evidence for this release is recorded separately in the latest handoff.

A focused Platform Admin workbench for tenant operations (v9.7.0)

Platform Admin now presents Overview, Tenants, Plans and Audit Logs as one active workspace at a time. Hash links remain available for direct navigation, while the sticky header no longer covers the current workspace title or its primary action.

Refresh evidence stays visible in the workspace: loading, ready, partial-load and retry states are distinct, and the last successful refresh time is retained. Tenant details and audit events open in a responsive reading drawer; Support Mode requires a focused, field-level reason; plan forms show field-level errors before a request is sent.

Subscription lifecycle copy now says “Subscription past due”; this release does not add online payments, bank-transfer configuration, Gmail/SMTP, AWS SES, SMS, SSE, WebSocket or browser push.

The exact source, package and production evidence for this release is recorded separately in the latest handoff.

A wider, better-aligned Studio Admin workbench (v9.6.1)

The Studio Admin shell now uses the available desktop canvas like the CMS. The navigation rail stays compact, the editor and preview keep a balanced working ratio, tablet layouts stack before content becomes cramped, and mobile remains single-column without horizontal overflow.

The preview starts in the active admin language so the shell, draft notice and save status stay aligned. Its own language control still supports an explicit independent bilingual comparison.

This is a presentation and language-alignment release only. It does not change the data model, permissions, publishing contract, payments, bank-transfer display, persistent CMS notifications or external messaging providers.

Production acceptance: v9.6.1 is running at pwestudio.online from candidate commit e46a3e3f4a407e8b2ac34ce8e230165c37150ea1. Deep health reports appVersion=9.6.1, a healthy database and all six stored tenant themes readable.

A clearer Studio Admin workbench for public publishing (v9.6.0)

Studio Admin now groups its work into Brand & Website, Admissions, Publish and Insights. Registration and public timetable controls sit together under Admissions, while family-message templates remain in Studio Admin and keep the existing CMS copy workflow.

Timezone, timetable and message edits now participate in unsaved-change protection; Registration shortcuts and workbench views are deep-linkable; timetable labels are bilingual; and the preview clearly says it is a private draft until Publish.

Online payments, bank-transfer configuration, Gmail/SMTP, AWS SES, SMS, SSE, WebSocket and browser push remain deferred.

Production acceptance: v9.6.0 is running at pwestudio.online from candidate commit f9007855dcaa10298bd522c82e7397d2afba0638. Deep health reports appVersion=9.6.0, a healthy database and all six stored tenant themes readable.

A calmer CMS information architecture for daily operations (v9.5.0)

The CMS now has a stable top bar, grouped navigation, role-specific workbenches and route-aware deep links. Today, Teaching & Operations, Business and Records give each task one clear home; System Settings is a full workspace instead of a large modal.

Courses, works, students, pending requests and recharge/refund operations have dedicated workspaces while existing role boundaries remain enforced. The layout uses the PWE Brand tokens, a balanced rail/content measure and 44px mobile action targets.

Production acceptance: v9.5.0 is running at pwestudio.online from release commit 9a976215bab9d5b32b9792f36851078a4111ff4b. The public deep-health contract reports a healthy database and all six stored tenant themes readable.

Persistent CMS notifications without an external messaging provider (v9.2.0)

New public registrations and class-booking requests now create a durable in-app notification in the CMS in the same transaction as the request. The notification bell shows unread items, each operator has independent read state, and a 30-second refresh plus a popup prompt surfaces new work without adding Gmail, SES, SMS or browser push infrastructure.

Online payments and bank-transfer configuration remain intentionally deferred while the first notification workflow is validated.

Course Schedule: a clearer name and a calmer working order (v9.1.1)

The CMS page formerly called Daily Roster is now Course Schedule. Date and week navigation, the attendance summary, class-time groups and adding a student now read from top to bottom as one planning task. On wide screens each student stays on one compact row; on phones the same controls keep a clear task order without horizontal overflow.

The three-dot menu now starts with the student's date, time and credit balance, identifies recurring-schedule entries, and groups status, reminder, one-to-one, undo and removal actions by meaning. Scheduled and make-up status changes are saved directly and audited instead of asking staff to remove and re-add the student.

A faster daily roster with safer delivery underneath (v9.1.0)

The daily roster is now one compact planner: date and week navigation, attendance summary, time groups, adding students and batch actions sit in the order the front desk uses them. Each student row has one clear check-in-and-deduct action; reminders, one-to-one marking, undo and removal remain close by without competing for attention. Birthdays and recurring schedules are still available, but folded until needed.

The dashboard now shows exactly which students are ready for the private portal, missing contact details, blocked from private content, ready to publish work, or missing publication consent; every number opens the matching student list. New public timetable requests alert the studio only after the request is saved, and tapping twice never sends two alerts.

Images now use phone-, tablet- and display-sized privacy-safe versions, so small screens no longer download the largest file. Authorized private images can revalidate without being made public, and every application asset carries a content hash so a browser cannot pair old JavaScript with a new release.

One Brand contract and a safe CMS migration baseline (v9.0.0)

The product now has one canonical Brand document, one bilingual system type stack for operational interfaces, and one explicit release ledger that keeps source code, packages and deployed production separate. A version label alone is no longer presented as proof that the same code was packaged or deployed.

Front Desk can review class-booking requests through a narrow server permission, but cannot change courses, capacity or schedules. The current CMS buttons remain restricted to Owner and Manager, so this permission does not silently broaden the visible interface.

The operational CMS also received its first deliberately small component migration: malformed touch and button-state selectors were repaired, and EmptyState now consumes semantic theme tokens without changing its data, props or callbacks. A real 390px Chromium check verified a 44px action target, visible keyboard focus and no horizontal overflow.

A timetable families can read, and a place they can ask for without an account (v8.9.0 – v8.10.3)

Your upcoming public classes now have a page of their own, linked from your site's navigation and reachable at its own address, so it can be forwarded to the other parent without forwarding the whole website. It is a page rather than another band on the home page because a family reading a timetable is holding rows against a calendar, and that wants width and a link of its own.

A class appears there only if you ticked it, one at a time. Scheduling a class and advertising it are different decisions, and the difference is the part that matters: one-to-one slots, internal make-up lessons, a trial place held for one family. You choose how many weeks ahead to show, and which of six facts each row carries — teacher, room, age range, finish time, places left, price — with a switch that shows a fact only when there is one, so a studio that never records a room never prints an empty "Room".

Places left are shown in words as well as colour — "3 places left", "Nearly full", "Full · waitlist" — because a colour-blind visitor, a greyscale print and a screen reader all have to reach the same three states. A full class is grey, not red: it sold out, which is an achievement, and red is kept for things that actually went wrong.

And a family can now ask for a place without opening an account: a full name and a phone number, no password. The request arrives in your console, holds no seat until you approve it, and the capacity is checked at that moment rather than when they tapped — so two families asking for the last place is handled honestly instead of quietly overbooked. Approving someone already enrolled puts them on that day's roster; approving somebody new starts an ordinary enquiry. The two are never counted as one, because "new enquiries this month" is how you judge whether your advertising worked.

Times are resolved in your studio's timezone on our side, not in the visitor's browser — a parent opening the page from another country sees your Wednesday, not theirs. A week you close is struck through with its reason rather than removed, because a class that silently disappears looks like a broken website.

A readable dark mode, and classes that know who teaches them (v8.8.0)

Dark mode was too dark, and that was measurable rather than a matter of taste: the page sat at or below the darkest surface any reference recommends, with several themes closer to pure black than to it. It is now a surface you can see rather than a void. Raising it forced three other things to be re-solved — an accent colour that had only ever been checked as a button and not as a link, status chips carrying barely more colour than the page they sat on, and brand chips that could converge with status chips. All of them were already wrong; the brighter page is what made them visible.

A weekly class can now name its teacher, its room and the course it belongs to, and can be marked for a public timetable that arrives in the next release. Publication is off by default and chosen one class at a time — "every class we have scheduled" and "every class we are advertising" are different lists, and the difference is the sensitive part: one-to-one slots, internal make-up lessons, a trial place held for one family.

A teacher's name on the public internet needs that teacher's agreement, not the class's. The switch is per person, defaults to off, and can carry a professional name such as "Lucy 老师" instead of the one on an identity document. With it off the timetable still shows the class; it simply shows no name.

And a recurring class can now be cancelled for one date, with a reason that visitors will see. Without that, a published timetable is a promise that cannot be withdrawn: you close for a public holiday and the site still says Wednesday at four, and a family drives across town for nothing.

A portfolio that scales with your plan, and a viewer worth opening (v8.7.0)

Selected Work now publishes 15 pieces on Starter, 60 on Studio and 150 on Growth. The number governs how many appear on your site, never how many you may keep: if you move to a smaller plan, every piece stays in your console, still editable and still reorderable, and the site shows the first ones. Reorder to choose which. Move up again and the rest reappear immediately, because nothing was deleted.

Pieces can be filed into categories — up to eight, in both languages — and visitors get filter buttons once there are two or more. Deleting a category never deletes work; those pieces simply become uncategorised. Categories are not limited by plan: what you pay for is how much you show, not how tidily you keep it.

Uploading changed shape. Drag a folder of photographs in, or pick many at once; each one appears immediately with its own progress. Photographs are now resized in your browser before they are sent — a phone photo that used to be too large to accept arrives in a fraction of the size, which also means your storage holds far more work. Portrait photographs keep their orientation.

And clicking a piece now opens it properly: arrow keys or a swipe to move between works, Escape or your phone's back button to close, and the focus returns to where you were. Videos play here at full size. The back button matters more than it sounds — before this, tapping back to leave a photograph would have taken a visitor off your site entirely.

Show your own work, not only your students' (v8.6.0)

Until now a studio site could prove what students had made, and not what the studio itself can do. The principal section was a portrait and a paragraph — a claim, not evidence — and for a parent choosing between two studios, the evidence is the part that decides.

There is now a Selected Work section, with its own tab in Studio Admin. Up to twelve pieces, each with a photograph and a bilingual title and caption. The first is shown larger than the rest, because a portfolio has a strongest piece and an even grid says everything is worth the same. It sits directly after the principal, and stays separate from the student gallery — the two answer different questions and should not share a heading.

Video is linked rather than uploaded: paste a YouTube, Vimeo or Bilibili address and only the cover image uses your storage. Nothing is requested from those sites until a visitor actually presses play — an ordinary embed costs several hundred kilobytes per video before anyone has asked to watch, and that cost is paid by the visitor's phone, not by us.

An outage we caused, and what now stops it recurring (v8.5.4)

Between 6 and 7 August, five of six studio sites served no content. The pages loaded, but the request that carries a site's words and images — its headings, its principal's biography, its contact details, its photographs — failed. Anyone who visited saw an empty page.

The cause was ours and it was small: v8.5.2 renamed one internal identifier for the "Custom" palette, and the sites still holding the old name could no longer be read. No studio lost anything. Every word and every image was in the database throughout, untouched, and returned the moment the fix deployed.

The part worth stating is why we did not notice. Our deployment checks confirmed the service was running and the database was answering — and they passed, correctly, the entire time. Neither question was "can this release still read the studios inside it?" That check now exists and runs on every deployment: if a single live site cannot be read, the release is rejected and rolled back automatically before it can reach anyone.

Also in this release: an "About the space" section for the public site — heading, description, up to six photographs and three highlights, all bilingual — which the site could already display but which no studio had any way to fill in. Its fields were being cleared on save. If you had written anything there through another route, please enter it again. The same applies to the two search-engine fields (page title and description), now editable in the same tab.

And the studio site's Latin display typeface now actually loads. It had been requested from an external service that our own security policy blocks, so every site had quietly been falling back to a system font since that policy shipped. It is served from our own servers now, which also means visitors in mainland China no longer wait on a request that would not have completed.

Eight named themes, and an industry that recommends instead of repainting (v8.5.0–v8.5.3)

v8.5.0 found a defect nobody had measured: because each theme's PAPER carried its own hue, whichever status colour shared that hue stopped being visible. A green theme could not show "saved"; a blue one could not show a notice. Five of the seven light themes had one of these. The repair was to give every status chip a floor on how much colour it must carry, independent of the page it sits on — so success, warning, danger and info are now recognisable on any of the papers.

A studio whose brand colour matches none of the eight picks the "Custom" card and sets its own, normally straight out of its logo. Only the hue of that colour is used: the depth and the intensity are solved by the system against measured contrast targets. A fluorescent logo becomes a proper deep green rather than a call to action nobody can read, and a colour that would be mistaken for a status is moved out of the way and says so. An industry template changes the vocabulary, the section headings and the enrolment questions — it does not repaint the site.

The public site also got its shape back. Every corner on it was 2 or 4 pixels, which reads as a form; it now uses a five-step soft scale and two levels of elevation, and the hero image carries a single hand-drawn organic edge. This changes no colour at all — it was simply the largest visual difference between this product and the studio sites it is meant to look like.

v8.5.1 answered the first thing owners said about it: the colour choice had stopped looking like a choice. There is now a row of seven starting colours to pick from before the free picker, the industry cards no longer carry a swatch bar promising a palette they no longer set, and the hero image can be cut to a rectangle, an oval or the organic shape rather than always the last one.

v8.5.2 corrected the correction. The real defect was never that eight themes existed — it was that selecting an industry silently wrote that industry's recommended palette over whatever a studio had already chosen. Removing the eight themes to fix that removed the choice as well, and the first owner to open the console said so. The eight named moods are back, each a complete palette with its own paper, ink and accent; the industry now only badges one as "recommended"; and a ninth "Custom" card opens the colour picker for a studio whose brand colour is none of them. The defect that was blamed on having eight themes — a green theme unable to show "saved" — stays fixed, because it was fixed in the generator rather than by deleting the variety that exposed it: all 1080 colour assertions pass on the original eight hues.

v8.5.3 fixed two section switches that were only half-connected. Switching off "Courses" or "Student works" removed the entry from the site menu and left the section itself on the page — the studio watched it disappear from the navigation and reasonably concluded it was off, while a visitor scrolling past still saw it. Both now hide the section as well, including in the case that hid the bug: the page loads its content and its settings in two independent requests, so whichever arrives second used to win.

One colour system instead of nine, and dark mode reaching the parts a palette cannot (v8.4.0, extended in v8.4.1 and v8.4.2)

The public studio site has had eight solved colour themes for a while. The rest of the product did not: the studio console declared 45 colours of its own, 33 of them stock framework defaults sitting on warm paper they were never designed for; the platform console had a second, different set; the password page and the shared portfolio page each had a third and a fourth. Seven palettes in one product, sharing eight token names that meant different things in each. That is why dark mode could never simply be switched on — there was no single thing to switch. All of them now come from one generator, which checks 976 colour pairs on every build.

Dark mode itself was failing in places no palette could reach. Scrollbars, dropdown lists, checkboxes and the browser's autofill are drawn by the browser and read no colour setting; on a dark studio site they all stayed light. The back-to-top button was a fixed cream circle under text that goes light in dark mode, so the arrow was invisible on all eight dark themes. The phone address bar stayed cream above a near-black page. All fixed, and each is now checked.

A studio can now set its site to follow each visitor's device, so a parent opening the enrolment page at night sees the dark palette. Both palettes are published when that is switched on. And uploading a hero photo now actually shows it — the upload filled in the address but left a separate dropdown on "Soft Art Board", so the photo was saved, published, and never displayed.

v8.4.1 carried the same work into the operations CMS, which turned out to have a hand-built dark palette with the cards drawn darker than the surface beneath them — the defect the studio themes had fixed a release earlier, still live here because this was a separate set nobody regenerated. The student registration page had a ninth palette of its own. Both now load on the same paper as everything else. Dark cards also sit further off the page than they did: the amount they lifted was correct as arithmetic and too small to see, so it is now measured the way a person perceives it rather than the way a number reads.

v8.4.2 found why the CMS had resisted every earlier attempt. It is built with utility classes generated in the browser, and the fix so far had been a layer of override rules chasing those classes after the fact — a layer that reached just over half of them and had to grow every time a component was added. It now configures the generator instead, so all of them follow the studio's palette. The rule that had been impossible to express: the grey scale has to flip between light and dark, because a pale grey is a background in one and text in the other, while a red button stays a red button in both.

A workable studio console, and dark themes that stack the right way (v8.3.0, corrected in v8.3.1)

The Website & Brand console spent more than half of a laptop screen on itself before the first control: a title bar, a section title repeating it, and a panel of description repeating that. On a phone the first editable field sat more than a full screen down, and nothing stayed pinned while you scrolled — not the tab you were editing under, not the Publish button. Two of those layers are gone and the third is a single row; the phone now pins the tab strip and the publish bar. Ninety-four controls that were too small to tap reliably have been brought up to size.

Separately: all eight dark colour themes were arranged upside down. The alternating band behind a section came out brighter than the cards sitting on it, so the cards read as holes. Every colour in them passed its contrast requirement, which is why the checks had always been green — contrast says whether text can be read, not which surface should look nearer. All eight are re-solved, and the check that runs on every build now tests the arrangement as well as the contrast.

Industry presets: the wording shown on an industry card and the wording published to the live site were two separate texts, and in Chinese five of the eight had drifted apart — the card promised one headline and the site went live with another. They are one text now. The registration page headings and intros were also rewritten so that both languages say the same kind of thing, and the intro names the questions that will actually be asked.

Correction to the previous release (v8.2.31)

The v8.2.30 release briefly showed a block of program code across the top of the platform console, and the date check it was meant to add was not actually active. Both are corrected. No customer-facing page was affected and no data was involved.

Saving a studio works again, and the subscription dates now mean something (v8.2.30)

Editing a studio that already had a Studio Admin login had been failing since 10 July: the save returned an error and changed nothing at all, unless a new password was typed each time. That is fixed. The four subscription dates are also checked against each other now — a trial that ends before the subscription starts, or a cancellation dated before the period it cancels, is refused with a sentence saying which two dates disagree, instead of being stored. And a new view lists every subscription that has passed one of its dates: a trial that ran out, a billing period that lapsed, a cancellation date that went by. Nothing in the product read those dates before; a studio could pass all three and the console still showed green. The list reports only — moving a studio is a separate, deliberate action, and a lapsed trial is always left for a person to decide.

Platform console: two data-loss defects, and the family identity (v8.2.29)

Opening a studio in the platform console, changing anything, and pressing Save cleared all four subscription dates. The dates arrived from the API in one format and were read as another, so every date field rendered empty and the empty value was what got saved. A second, separate path cleared the trial end date on every save regardless. Both are fixed, and the server now keeps a date it was not asked to change. The console also received the studio identity it never had — warm paper, navy ink, one amber accent instead of five unrelated colours — and the tenant detail view became five tabs instead of one wall of cards that rendered seven of its fields twice.

Findable, and readable by machines (v8.2.28)

Every WebP image on the site — including the one used as the link preview — was being served with a file type that says “unknown binary”. Browsers guessed correctly, which is why nothing looked broken; social platforms do not guess, so a shared link showed no picture. Fixed, along with caching: the manual’s screenshots were re-downloaded on every visit and are now held by the browser. The site also gained a sitemap, a robots file, and machine-readable pricing at /pricing.md and /llms.txt — the pages an AI assistant reads when a studio owner asks it what to use. The service FAQ, terms, privacy and support pages now each have a Chinese address of their own instead of a language switch inside one page.

Media uploads repaired (v8.2.6)

Every image upload — studio logo, home image, student photo, portfolio — was failing in production. Uploads work again, and a photo now costs the server about an eighth of the memory it did: a 24-megapixel file went from 139 MB of peak memory to 17 MB. Files beyond 30 megapixels are refused rather than allowed to exhaust the instance.

Operation log records everything (v8.2.3)

The studio operation log only ever showed check-ins and credit changes; archiving, renaming, scheduling and portfolio edits were performed but never listed. Every operator action is now recorded with the person who took it.

Theme colours resolved as a set (v8.2.7–v8.2.9)

Three rounds of work on the eight studio themes. Large areas now stay in the brand's own colour family instead of being split by a second, near-opposite hue; and success, warning and danger are solved per theme so a warning badge can never end up looking like an ordinary button. All 45 status colours were re-derived against measured contrast targets.

Archiving and deleting a studio (v8.2.10)

Archiving a studio returned a server error and had never once succeeded in production, which also left permanent deletion unreachable. Both work, and each writes a full snapshot — database records, workspace and media — before anything is removed.

Data retention (v8.2.19)

Audit records, analytics events, notification records and access sessions previously had no expiry. Retention now applies on a schedule — audit records are kept two years, analytics one year — so the service does not accumulate indefinitely. Consent records are deliberately exempt and are never deleted.

The manual prints properly (v8.2.22–v8.2.23)

Printing the manual put body text on top of the page footer and produced 28 pages for what fits in 18. Both are fixed: nothing overprints, and a printed copy is a third shorter. The version and the licence are stated on the first page, and your browser's own print settings add the date and page numbers.

User manual (v8.2.21)

A full user manual is now published at pwestudio.online/manual/ — how to get your website live, take enrolments, run the roster, handle credits and refunds, publish student work with consent, and what each role on your team can and cannot do. Chinese at /zh/manual/. It prints to a clean PDF, and every printed page carries the version and the date so an old copy says what it is.

English interface completed (v8.2.21)

Sixty-six strings in the operations CMS were still Chinese when the interface was set to English — most of them button labels read aloud by screen readers rather than text on screen. All are translated, and a check now runs over every screen so the gap cannot reopen quietly.

Pricing comes from the plan table (v8.2.19–v8.2.20)

The public pricing page used to state its plan limits as fixed text, and they had already drifted from what the product enforces. The page now reads the plan table directly, so a figure it prints is a figure the system honours. A plan is also no longer published simply because it exists: publication is a setting an operator turns on, which keeps internal and test plans off the public page.

Product website rebuilt (v8.2.20)

The home page was rebuilt on the studio's own design system and now follows the reader's light or dark system setting. English and Chinese have separate addresses — pwestudio.online and pwestudio.online/zh/ — instead of both rendering into one page, so each is a page in one language for readers and for search engines alike.

Platform console (v8.2.4–v8.2.11)

The console was reorganised around what an operator does with it: what needs attention today first, standing totals next, analysis last and collapsed. Its counters are now filters — clicking one lists exactly the studios it counts. Phone layout was rebuilt so the tenant table reads as cards rather than a sideways-scrolling grid.

What v8.1.0 changes

The previous release was accepted for local demonstration only. This one takes the service into production, then fixes what going live and a full readability review exposed. Nothing below is a plan; each item is already in the release.

Production hosting

The service moved to a dedicated AWS instance on 30 July 2026 with its own certificate, daily database backups and a rehearsed restore. The tunnel used for earlier invitation demonstrations is no longer part of the production path.

Registration confirmation is readable again

On the seven dark studio themes, the card a parent sees after submitting a registration painted fixed light text on what the theme had turned into a light surface — measured at 1.06:1, effectively invisible. It now takes both colours from the theme, a pair the palette generator already checks at 4.5:1 or better across all fifteen theme variants.

Your branding now reaches the CMS

The daily operations workspace applied only part of a studio's chosen theme and then painted a fixed grey background over it, so every studio's CMS looked the same. The public portal, the registration page and the CMS now apply one identical, complete theme set, with a test asserting the three agree field for field.

Focus and form outlines meet the standard

The keyboard focus ring on the product homepage measured 1.70:1 against the page, below the 3:1 a non-text indicator requires; it is now 4.52:1, and the brighter identity amber is kept where it is correct at 9.70:1. Form field outlines on dark sections moved from 2.51:1 to 3.90:1.

Plan allowances revised

Monthly prices are unchanged. Starter now includes 1 team account and 2 GB; Studio 5 accounts and 10 GB; Growth 1,000 students and 50 GB, keeping its 20 team accounts. Exceeding an allowance refuses the next addition — it never deletes existing students, accounts or media.

Published policies

A privacy policy and terms of service are now published rather than promised, naming the operating entity and its ABN. Both are drafts pending Australian legal review and say so on the page.

Customer outcomes carried forward

Brand-led entry

Canonical PWE Navy, Amber and Warm Paper with approved sales copy, clear role entrances and demonstration actions.

Safe showcase

An isolated Let’s Paint Studio tenant with fictional records, synthetic artwork and a guarded one-click reset.

Connected workspaces

Studio Admin for website and brand, CMS for daily operations, with stable switching between them.

Family loop

Credit balance, next class, attendance, portfolio and device-native studio contact.

Scheduling

Real recurring group rosters and a privacy-safe ICS calendar download that carries no student identities.

Commercial delivery

Onboarding, FAQ, migration templates, support policy, pricing, agreement draft and security disclosure.

Production deployment, 30 July 2026

The earlier editions of this page said AWS production acceptance was deferred. That is no longer accurate. The table records what was established, measured from outside the instance.

v8.1.0 itself, including the revised plan allowances, has since been deployed to the same instance and is what the service runs today. Every deployment backs up first and rolls itself back if the service does not come up healthy.

Item Established
Public service v8.1.0 served from an AWS Lightsail instance in the Sydney region
Transport TLS terminated at the host; HTTP 301 to HTTPS in one hop; HSTS one year; certificate chain verifies; auto-renewal timer active
Exposure Application bound to loopback only; no absolute http:// references on the homepage, and a self-only content policy makes mixed content structurally impossible
Canonical host One origin: www redirects permanently to the apex over TLS
Database PostgreSQL 16, 20 migrations applied; runtime uses a restricted role, the owner role only for migrations
Backups Daily logical dump plus media-volume archive; restore rehearsal runs and passes
Rollout safety Deployment refuses a standalone-mode artefact, backs up first, and rolls back automatically when deep health fails
Availability during upgrades Branded maintenance page with a retry hint replaces the stock gateway error while the container restarts

Four defects this deployment uncovered

All four looked fine from the outside and would otherwise have surfaced during an incident. They are listed because a release record that only lists successes is not evidence.

Daily backups had never succeeded

The scheduled job called the backup script at the wrong path inside the image, and nothing read its output. Fixed, and the job now fails loudly.

The dump could not be written

The backup directory’s ownership did not match the container’s user, so writes were denied. Ownership and mode are now asserted on every run, and an operator can still list backups without elevated rights.

The restore rehearsal could never pass

An unpinned client package resolved to PostgreSQL 17 against a version 16 server, emitting a setting the server rejects. The client is now pinned to 16, and dumps produced by the newer client were deleted rather than left to fail mid-incident.

The media volume was empty

The database referenced media assets and derivatives that the volume did not hold, so every brand logo returned a not-found. The media tree was restored, and the variant tool now verifies that a derivative file exists rather than only its database row.

Still deferred

What we do not claim

A final privacy policy, service agreement and data-processing schedule still require Australian legal review. The published privacy policy and terms of service are drafts that describe actual product behaviour; they are not legal advice.

Acceptance gates

Gate Required evidence Status
Backend Full PostgreSQL verification passes Passed
Calendar privacy Timezone and recurrence valid; no student data present Passed
Demo reset Guard refusal proven, then an isolated successful reset Passed
UI Browser checks at 375, 768, 1024 and 1440 px Passed
Theme publication Portal, registration and operations workspace apply the same complete theme; no public surface pins a colour the theme should own Passed
Public-surface contrast Text and focus indicators on customer-visible surfaces meet the standard across every theme variant Passed; the operations workspace has two open items listed above
Templates CSV and the multi-sheet workbook rendered and inspected Passed
Packages SaaS and Edition builds inspected; mode-specific contents asserted Passed
Deployment Public HTTPS, DNS, certificate, redirect, deep health and data counts Passed 30 July 2026
Recovery Database and media restore rehearsal from a real backup artefact Passed on-instance; off-instance copy open
Privileged MFA Second factor enforced for every privileged account Open
Monitoring and SLA Uptime and backup-failure alerting, on-call roster, signed availability target Open