- Overview: per-currency outstanding with overdue emphasis, work counts, overdue invoices, receivables by age, relative due dates, foreground reload, and native loading/empty/error states. - HIG pass: standard two-column rows, plain sentence-case statuses (red only when overdue), record names as detail titles, readable dates, in-list filters, labelled login fields with Return-key flow, device name no longer defaults to "iPhone", revoke button no longer fills the row, dialogs anchored to their buttons, tappable email/phone. - Invoice PDF: fetches GET /api/v1/invoices/:id/print, renders A4 pages through WebKit's print path, draws the per-page bar and supergraphic natively, waits for the inline Montserrat, and opens QuickLook with share/print. Hidden on servers without printVersions. - Docs: spec moves PDF viewing out of deferred; backend handoff notes. Co-Authored-By: Claude Opus 5.5 <[email protected]>
NPInv for iOS
Native, read-only companion to the self-hosted Naspad Studio dashboard. Browse invoices and balances, clients, projects, and task checklists. Business-data editing is deliberately deferred.
Run on your iPhone
- The matching backend is deployed at
https://invoice.naspadstudio.id(application commitbf69a9d, deployed 2026-10-15). - Open
NPiOS.xcodeprojin Xcode. Choose the NPiOS target, set your signing team, and select your connected iPhone (iOS 17+) or an installed iOS simulator. - Run the app. Use your existing dashboard network access.
- Enter
https://invoice.naspadstudio.id(no/apisuffix), a recognizable device name, and your existing admin password.
The password is used only at login and is never saved or bundled. A random, 30-day device credential is stored in Keychain with device-only, unlocked accessibility. HTTPS uses normal system certificate validation. The app refuses redirects and does not send tokens to a different server.
You can revoke individual sessions in More → Device sessions, or in the web dashboard's Settings → Mobile devices. Changing the admin password invalidates all device sessions. Sign out revokes the current credential and clears local state. If the server is unreachable, local sign out still works; revoke that session from web Settings to confirm removal on the server.
Structure
Models.swift: Codable records, envelopes, and exact integer money formatting.APIClient.swift: HTTPS URL validation, URLSession, bearer headers, response errors.SessionStore.swift: Keychain, login/logout, foreground session validation.PagedModel.swift: main-actor observable list/detail state and stale-response handling.- SwiftUI screen files: native navigation, read-only lists/details, and session management.
No third-party packages, local business database, or offline write queue.
Verify
The core is also a Swift package so its tests can run without a simulator:
swift test
Compile the complete iOS interface without signing:
xcodebuild -project NPiOS.xcodeproj -scheme NPiOS \
-destination 'generic/platform=iOS Simulator' \
-derivedDataPath /tmp/npios-derived CODE_SIGNING_ALLOWED=NO build
Install an iOS simulator runtime through Xcode Settings → Components before trying
to launch a simulator. Real-device installation requires your signing team.
See docs/verification.md for the checks actually completed.