Promotional Discounts (9 marketplaces), German singular credit forms, Belgian
Total Discounts, Italian Marketplace Withheld VAT, the Turkish native headers,
and 8 Transaction Release Date translations. Unmapped amount columns raise
unmapped_amounts errors that block control C2, so these close real gaps.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Deliberate for the small internal team - a clear 'is not a registered
account' beats the anti-enumeration non-answer that read as success.
Successful sends now name the address and expiry.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
New POST /api/auth/verify-code checks the code without consuming it
(wrong guesses still count toward the 5-attempt lockout); the password
fields only appear after the code verifies. Email step hints that codes
go only to registered @utopiabrands.com accounts.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
login-screen forgot-password flow only
Also fix: the auth middleware now attaches the signed-in identity on
open paths too (a signed-in request-code call previously saw no user
and demanded a username).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
App README: password self-service in production behaviors, real test
count (155), SQLite-by-default dev note, stale status dump replaced
with a grouped feature summary. Root README: self-service reset in the
intro and quick-start table.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Same internal mail service the TikTok dashboard uses for its
verification codes: bearer-token multipart POST (stdlib urllib, no new
deps). Configured with AR_MAIL_API_URL/TOKEN; credentials live only in
the gitignored env files. Live send verified ({status:sent}).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
New flow (active once AR_SMTP_* is configured; hidden otherwise):
- POST /api/auth/request-code emails a code to the account address
(usernames are emails). HMAC-stored, 10-min expiry, single-use,
5-attempt lockout, 60s resend throttle, no user enumeration.
- POST /api/auth/reset-password sets the new password with the code —
works signed-in (Settings) and from the login screen (Forgot
password?), so users can self-recover without the admin.
- Mailer: stdlib smtplib (STARTTLS/SSL, certifi CA bundle); SMTP
settings documented in .env templates.
- Settings switches to the code flow when email is on; the
current-password form remains the fallback.
Note: CRAI_Report was checked as the reference for code-sending — it
has no email/OTP functionality, so this is a fresh implementation.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Navy brand panel (ledger-grid texture, purple glow, product pitch) +
sign-in form on the canvas: input icons, show/hide password, inline
error, entrance animation (motion-safe). Mobile collapses to the form
with a compact brand header.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
POST /api/auth/change-password requires the current password; admins
still reset others via manage.py set-password. UI on the Settings page
(signed-in users only) with match/length validation.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Month management & data separation:
- Fix double-count bug: re-uploading a filename updates the existing
session_files row in place; identical content (sha256) is skipped —
a closing can never parse the same file twice
- Guard against duplicate closings per reporting month (409 unless
explicitly overridden); dashboard flags duplicates
- Default new closings to carry-forward openings; month switcher in the
closing header; publish state visible everywhere; Accounts Summary
lists unpublished months with the reason instead of dropping them
- Completed closings are locked read-only with an explicit reopen
Authentication (stdlib only, no new deps):
- Per-user login (scrypt + HMAC tokens), AR_AUTH=auto turns on with the
first user; manage.py add-user/set-password/deactivate-user
- Verified identity feeds reviewed_by/approved_by/confirmed_by
Exchange rates:
- fx_service with provider abstraction: Frankfurter (free, keyless,
ECB) default, exchangerate-api stub; month-end + daily fetch
endpoints and UI buttons; rates arrive unconfirmed so Control C5
still gates the close; cache table; certifi CA bundle
Deployment & hardening:
- Production Docker stack: caddy (auto-HTTPS) + nginx + single-worker
backend + mysql:8.4; per-context .dockerignore (images carry no
financial data); .env.example with local+production sections
- deploy/DEPLOY.md runbook + nightly S3 backup script
- Stale-job recovery on startup; export retention (AR_RETENTION_DAYS);
deep /api/health; request/job logging; Gitea Actions CI
- Repo reorganized: launchers in scripts/, dated lowercase docs,
root README, .gitattributes for deterministic line endings
Tests: 152 passed (25+ new: dedup, month locking, auth, FX orientation)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>