account-settings and password-reset called clearMailpit in parallel with
other tests, wiping emails before waitForEmailChangeToken could read them.
Co-authored-by: Cursor <cursoragent@cursor.com>
Align AdminDashboard unit test with API error messages shown in UI.
Stabilize account-settings E2E by relying on waitForEmailChangeToken only.
Co-authored-by: Cursor <cursoragent@cursor.com>
Remove the brittle filter-empty assertion from admin search helpers.
Run deferred-payment-admin in an isolated Playwright project with one
worker so serial tests keep shared order state. Stabilize unpaid-order
lookup by searching order id first, then plate text from the admin row.
Co-authored-by: Cursor <cursoragent@cursor.com>
Merge admin lookup checks into one serial test, create the plate when
the order is created, and search using the plate shown in the admin row.
Co-authored-by: Cursor <cursoragent@cursor.com>
CI intermittently failed when searching admin orders by registration
number because the table was queried before data and filters settled.
Wait for the admin list to load, clear the search field between queries,
and use a longer timeout when expecting the matching row.
Co-authored-by: Cursor <cursoragent@cursor.com>
Mobile traffic was breaking on narrow viewports because the header nav
overflowed and several pages used desktop-only spacing. This adds a
shared phone breakpoint, a hamburger menu, and scroll-to-top on route
changes so footer and menu navigation always land at the top of the page.
- Add --page-gutter and max-width 639px rules in base.css
- AppHeader: hamburger panel on small screens; flat account links on mobile
- AppFooter: stack footer links vertically on phones
- Home, compose, edit order, orders, auth, and legal pages: tighter gutters
and responsive layout (orders card actions stack; home grids single-column)
- Router scrollBehavior: scroll to top on navigation; restore on browser back
- Tests: AppHeader menu toggle, Router scrollBehavior, mobile Playwright checks
Admin page is intentionally unchanged.
Co-authored-by: Cursor <cursoragent@cursor.com>
Replace the header "Byt lösenord" link with an Inställningar menu for
changing email or password. Email changes are two-step: request with
password, confirmation link to the new address, then password again on
confirm so a wrong inbox cannot take over the account.
- Backend: EmailChangeService, V10 email_change_tokens, confirm API
- Frontend: ChangeEmailPage, ConfirmEmailChangePage, header dropdown
- E2E: account-settings round-trips, Mailpit verification, wrong-password guard
- Flyway: V9 restore for dev DBs, CI migration checks, V10 for email tokens
Co-authored-by: Cursor <cursoragent@cursor.com>
- Create TermsOfServicePage covering Swish payment, letter content rules, and liability
- Describe edit/cancel before payment and refund expectations after posting
- Link to integritetspolicy and support contact in footer CTA
- Add TermsOfServicePage unit tests
Co-authored-by: Cursor <cursoragent@cursor.com>
- Create PrivacyPolicyPage with sections on data, rights, and letter recipients
- Use plain Swedish without technical jargon or operational detail
- Link to kontakt page and mailto for privacy questions
- Add PrivacyPolicyPage unit tests
Co-authored-by: Cursor <cursoragent@cursor.com>
- Add support@bilhej.se for orders and technical issues
- Move complaints to klagomal@bilhej.se instead of personal Gmail
- Show one mailto chip per card instead of duplicate link and button
- Update ContactPage tests and production email checklist for all @bilhej.se addresses
Co-authored-by: Cursor <cursoragent@cursor.com>
- Move the three explanatory paragraphs into the hero card under the lead
- Remove the separate "Vad vi gör" section that repeated the same framing
- Add a light divider between lead and body text for readability
Co-authored-by: Cursor <cursoragent@cursor.com>
- Add production checklist section for Resend inbound on bilhej.se
- Note that mail is read in the Resend dashboard unless a webhook is added later
- Update GDPR letter footer example in REQUIREMENTS.md to kontakt@bilhej.se
Co-authored-by: Cursor <cursoragent@cursor.com>
- Truncate previews over 120 characters with a Visa mer toggle
- Allow per-order expand state on pending and completed cards
- Add styles for expanded preview and toggle button
- Cover long and short message behavior in OrdersPage tests
Co-authored-by: Cursor <cursoragent@cursor.com>
- Replace obsolete hej@bilhalsning.se in ComposePage GDPR footer
- Apply the same correction on EditOrderPage for edited orders
Co-authored-by: Cursor <cursoragent@cursor.com>
- Replace single placeholder mailto with two contact cards
- Show kontakt@bilhej.se for general questions and service issues
- Show jcamorling@gmail.com for complaints with clearer labeling
- Add tips section pointing users to Mina beställningar first
- Extend ContactPage tests for both email addresses
Co-authored-by: Cursor <cursoragent@cursor.com>
- Replace placeholder about card with hero, prose, steps, and CTA
- Add primary route /om-oss with redirect from legacy /om
- Update footer tagline and Om oss link to match new URL
- Extend AboutPage and AppFooter tests for new content and routing
Co-authored-by: Cursor <cursoragent@cursor.com>
- Add structured use-case cards mapped to real letter templates
- Replace generic hero with bullets on traceability, anonymity, and timing
- Add three-step how-it-works flow with manual posting disclaimer
- Reframe trust section around convenience rather than hidden addresses
- Refresh layout with gradient heroes, icons, and consistent section styling
Co-authored-by: Cursor <cursoragent@cursor.com>
The cancel API returned 500 because ck_orders_status did not include cancelled.
Adds Flyway V9 and an E2E test for cancelling a pending order from /orders.
Co-authored-by: Cursor <cursoragent@cursor.com>
Redesigns the order list so unpaid and paid orders share a consistent
card layout, with clearer payment context and labeled metadata users
need before paying via Swish.
- Split list into Obetalda/Tidigare sections with pending orders first
- Pending cards: preview box, labeled Beställnings-ID, price row, Betala 49 kr
- Completed cards: same header/preview layout, prominent Spåra brev button
- Replace em-dash pay label and update unit/E2E selectors
Co-authored-by: Cursor <cursoragent@cursor.com>
Adds backend endpoints and frontend edit page so pending orders can be updated or soft-cancelled without admin intervention.
Co-authored-by: Cursor <cursoragent@cursor.com>
Forgejo workflow_dispatch requires an explicit input type; without it the
UI showed invalidinputtype. Clarify README: workflow ref vs version tag.
Co-authored-by: Cursor <cursoragent@cursor.com>
The docker profile disables mail.smtp.starttls for Mailpit; prod runs
docker+prod so Resend saw AUTH before STARTTLS (538). Re-enable auth and
STARTTLS in application-prod.yml.
Co-authored-by: Cursor <cursoragent@cursor.com>
Deploy workflow now writes MAIL_* and APP_PUBLIC_BASE_URL from Actions
secrets into the server .env so Resend SMTP works after domain verify.
Document Resend-only setup, Forgejo secret names, and prod expose-token off.
Co-authored-by: Cursor <cursoragent@cursor.com>
Operators can fix prod admin passwords without email via Byt lösenord;
end users can use forgot-password when SMTP is configured. Local and CI
use Mailpit to capture outbound mail and verify reset links end-to-end.
- Backend: V8 password_reset_tokens, PasswordResetService, EmailService,
POST /api/auth/forgot-password, reset-password, change-password
- Optional testToken in forgot-password response (docker profile only, for E2E)
- Frontend: ForgotPasswordPage, ResetPasswordPage, ChangePasswordPage,
routes, login link, header Byt lösenord
- Mailpit (ghcr.io/axllent/mailpit:v1.28) in docker-compose + e2e stack
- E2E: password-reset.spec.ts + Mailpit API helper tests SMTP delivery
- Separate dev/e2e Docker image names to avoid overwriting bilhej-frontend
- Docs: README email section, production-email-checklist, .env.example
- Unit/integration tests for reset, change password, and Vitest page specs
Co-authored-by: Cursor <cursoragent@cursor.com>
First-time host nginx setup needs HTTP-only vhost before certbot can
issue certs; the full bilhej.nginx.conf 443 block fails nginx -t until
those files exist.
- Add docker/bilhej.nginx.http.conf for ACME phase
- Reorder README one-time setup: HTTP vhost, certbot, then full config
Backend crashed on startup because the prod DB still records V6 (and
possibly V2/V4) from when seeds lived in db/migration, while prod only
loads schema migrations. ignore-migration-patterns alone did not prevent
validate failure on the runner.
- Run Flyway repair before migrate on the prod profile
- Add ProdFlywayConfigTest for repair-then-migrate order
- Document the V6 error in README deploy troubleshooting
Root check only ran frontend lint, unit tests, and E2E, so backend JUnit
and JaCoCo gates were skipped despite AGENTS.md documenting otherwise.
- Make check depend on :backend:check and frontendE2E as siblings
- Update AGENTS.md comment to match the real task order
Production deploy failed with no backend logs before rollback. Print
backend and postgres logs on failure, wait longer for JVM startup, and
probe /api/payment/swish-info instead of vehicle lookup (no external scrape).
- Document proof-first troubleshooting in README
- No volume reset workflow; fix only after reading job logs
Docker Compose interpolates $VAR in .env files. Passwords like ...$A72y...
were truncated and the backend failed health checks, triggering rollback.
- Escape $ as $$ when writing production secrets to .env
- Document that deploy handles literal $ in Forgejo secrets
Local verification should match Forgejo CI. Wire frontendE2E into check
and point it at docker-compose.e2e.yml with the same test env vars.
- Add frontendE2E to check after frontend unit tests
- Run docker-compose.e2e.yml directly from Gradle with CI secrets
- Update npm test:e2e:ci to use the e2e compose file
The admin search label and parallel compose tests made strict-mode
Playwright locators ambiguous after the dashboard rework.
- Assert table columns via columnheader roles instead of getByText
- Target seeded order by ID when opening the message modal
Co-authored-by: Cursor <cursoragent@cursor.com>
Operators need IntelliJ-style GUI access to Docker Postgres and clear
steps for manual prod cleanup without wiping volumes.
- Add Database access section with IntelliJ, DBeaver, and SSH tunnel steps
- Document dev-only accounts, manual SQL cleanup, and hashPassword task
- Note Flyway dev-migration split and admin bootstrap in AGENTS.md
Production must not ship test users, demo orders, or test1234. Dev and CI
still need seeded users for e2e. Prod creates one admin from deploy secrets.
- Move V2/V4/V6 seed migrations to db/dev-migration
- Add application-prod.yml with schema-only Flyway and ignore-missing for moved seeds
- Add AdminBootstrap to create admin from ADMIN_EMAIL and ADMIN_PASSWORD
- Wire docker,prod profile, deploy secrets, and localhost:5433 for SSH DB access
- Add hashPassword Gradle task for optional manual bcrypt generation
Manual Swish flow means users often pay later; admins match payments via
order ID or regnr under Att göra.
- User flow: create order, leave payment, pay from orders page
- Admin: find order via partial ID, full ID, and plate search
- Assert unpaid orders appear under Väntar, not Att göra
- Use unique plates per run to avoid collisions with seed data
Admins need to find orders quickly and read full letter text without a
cramped table column.
- Make stat cards clickable filters (Totalt, Att göra, Betalda, Väntar)
- Add search by partial order ID or registration number
- Show shortened order ID in table with full ID on hover
- Replace message column with "Visa meddelande" opening a modal
- Keep expanded row for tracking only; remove duplicate brevtext block
- Update AdminDashboard unit tests and admin-dashboard e2e specs