All work

Atta Star web

Business control for my company: invoices read from their QR codes and matched to the bank, the timesheet, and the projects at a glance. The accountant has a read-only view of the books; a project manager at a client checks the hours billed to them and suggests changes, which come to me to approve.

Role
Sole developer: design, build and hosting
Year
2026
Outcome
One place to see what each project is waiting on, how the week's hours went, and which invoices and bank movements still need matching, without opening five tools.
Built with
Node 22, TypeScript, Vue 3, Pinia, SCSS, Vite, Vitest, Playwright, pnpm workspace
Atta Star web, the business overview: revenue and costs month by month, the bank, what clients owe and the tax estimates, on made-up data with the amounts hidden.
Screenshot on made-up data.

Why I built it

Working alone across several projects, the state of each one was spread around: git, to-do lists, notes and Claude Code session logs. Hours had to be rebuilt by hand at the end of the month, and the company's invoices and bank movements were matched in a spreadsheet.

What it does

  1. To do

    The Business page opens on one list of what is waiting on me: an e-Fatura import more than 35 days old, a line in e-Fatura with no document behind it, a photo whose code could not be read, an online order with no invoice, a request from the accountant, a statement for an account it does not know. The sidebar badge counts them, and anything before the date the books were closed drops off.

    Atta Star's Business page on its To do tab: a request from the accountant and three invoices listed in e-Fatura with no document yet, each with Scan, Link a document and Won't get it. Made-up data.
  2. Invoices read from their QR code

    Every invoice and receipt the company receives is filed by its Portuguese fiscal QR code, whether it came from the invoices mailbox, an upload or the phone's camera, which reads the code and then takes a photo to crop. The reader copes with codes drawn as images, as vector shapes or in a barcode font, with a second decoder as a fallback. Each document says what it is (a cost, a sale, not an invoice), can be marked as paid from my own pocket, and goes on to the accounting software.

    Scanning a paper invoice: the photo with crop corners and, below it, what its QR code says: the supplier's tax number, the invoice number, the total and the date. Made-up data.
  3. e-Fatura

    The tax authority's list of the month's invoices, received and issued, sits beside the documents. Each line is matched to its document or marked Missing, and can be linked by hand or waived.

    The e-Fatura tab: the tax authority's list of the month's invoices, each line beside its document or marked Missing with Link a document. Made-up data.
  4. Bank

    Accounts are read through PSD2 open banking, read-only, with consent given at the bank itself: once a day in the background, or on demand while I am there. Matching applies only the certain cases (bank fees, transfers between my own accounts, an exact amount within ten days of an invoice) and proposes the likely ones for one click. Statement PDFs fill in older history, and one whose running balances do not add up is refused whole. A separate section keeps the running balance between me and the company.

    The Bank tab with a client's transfer open: what the bank says, and a proposed match to an invoice to accept with Yes or No. Made-up data.
  5. Overview

    The year in accounting terms beside the cash in the bank: who owes what, months and quarters with VAT, a corporate-tax estimate, what is coming up, and years side by side. A year report prints in English or Portuguese.

  6. Timesheet

    Nobody types hours in. A small publisher on each of my computers reads the coding sessions and git state and sends working blocks across. The timesheet shows them by day, week or month, as a ledger, a calendar, per client or as an invoice. A block can be retimed, split, moved to another project, excluded or marked billable, and each client has a "billed through" date. It exports to CSV, Excel and PDF.

    The timesheet's ledger for one week: working blocks per client with summaries, one excluded block, one waiting for approval and one added by hand. Made-up clients.
  7. The accountant and clients

    The accountant gets a read-only view in Portuguese (documents, e-Fatura, bank and overview) and downloads a period as a zip, a spreadsheet or a monthly pack. A missing document can be asked for, and the request lands in my To do. A client sees only their own billable hours, without clock times or amounts, and can suggest a change or comment on a line. Suggestions wait in Approvals until I accept or reject them.

    The Hours page a client sees: their billable time by project and day, with no clock times or amounts, one entry waiting with the developer, and Save as PDF. Made-up client.
  8. Projects and wikis

    One card per project with its branch, uncommitted changes, last commit and open tasks, and links to the editor, the live site and its wiki. The shared knowledge base and every project's wiki can be read here, with an outline and search.

    The Projects list with one project open: its branch, uncommitted files, last change and open tasks. Made-up projects.
  9. Notifications

    Phone notifications only for what needs acting on: an invoice that turns 30 days unpaid (once, and not before nine in the morning), a lockout after repeated failed sign-ins, an off-site backup that has not arrived in 36 hours, and each connected app's daily nudge.

    Illustration: a phone with four notifications: an invoice 30 days unpaid, a backup that has not arrived, a sign-in lockout, and the day's nudge.

How it works

Sign-in and roles
A single sign-on page with two-factor sign-in stands in front of the app, which has no port of its own. One access module decides every route and refuses anything it does not allow. There are four roles: owner, collaborator, client and accountant. Anyone but the owner is refused a write before the request is even read, and every change must carry a custom header against cross-site requests. I can view the site as another user, read-only and audited. The audit log keeps every export, decision, invoice change and accountant read for 90 days.
Secrets
Keys come from a fixed, checked list, live in owner-only files and never reach a page. A page only ever sees the last four digits of an IBAN. Bank calls are signed with short-lived tokens. The tax portal password is never held: an Atta skill fetches the month's e-Fatura file in a browser where I sign in myself.
The publishers
Each computer gets its own token, shown once. Only its hash is stored; it is compared in constant time, can be revoked, and opens the routes that receive data and nothing else. Session transcripts never leave the computer, only working blocks with short snippets of each prompt. An edit made while the server cannot be reached waits in a local outbox.
The household finance app
The household finance app reads two figures from Atta Star through one read-only bridge, server to server: business invoices I paid with a personal card, and the running balance the company owes me. Its token opens that one path, the reply is capped in size, and every read is audited. Atta Star asks nothing back. Other apps can show a small status card on the Projects page, three lines at most, without Atta Star knowing what the numbers mean.
Storage
There is no database: data is JSON files, written to a temporary file and renamed into place. A file that cannot be read stops the route rather than being saved over. Open pages get changes over one event stream and reload only the part that changed.

How it is built and tested

Tests
About 2,500 unit tests and six Playwright suites: accessibility checks with axe, phone-width runs, and the business, approvals, client and documents flows. Each test was proved by breaking the code on purpose and watching it fail. Fake invoice PDFs with valid QR codes, fake statements, a fake bank and a fake Google stand in for the real ones.
Releases
Every pull request runs type checks, lint, tests, the build and packing. A merge publishes a release archive with its checksum. Nothing on GitHub can reach the server: the server pulls the release, checks the hash and the contents, and tests the new proxy configuration before reloading. The server is bundled into one file, with no node_modules.

How Atta helped

  • Every pull request went past atta-critic, an independent reviewer with no memory of the session that wrote the code. Its first real use caught two false claims in a PR description.
  • Open decisions were settled before code with /atta-grill, one question at a time, and the reasoning kept in the project wiki.
  • What it learned about banks, statements and invoices was written up in the shared wiki, so the household finance app started from it instead of from scratch.
  • The repo rule is no real figures: tests use made-up amounts and names, and a pre-commit scan refuses anything shaped like a tax number or IBAN.