Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
316 commits
Select commit Hold shift + click to select a range
b989f1d
feat(frontend): add accessible light/dark theme tokens + fonts in tai…
govargas Sep 14, 2025
c72805f
feat(frontend): add accessible light/dark theme tokens + fonts in ind…
govargas Sep 14, 2025
b0fca57
feat(frontend): update fonts links in index html file
govargas Sep 14, 2025
d0abd18
feat(frontend): integrate Header into App layout while keeping Routes…
govargas Sep 14, 2025
d5a503f
chore(frontend): ensure Tailwind theme includes quality colors + sema…
govargas Sep 14, 2025
a07a3c0
fix(frontend): replace theme() usages with utilities and keep @apply …
govargas Sep 14, 2025
d4e5fab
chore(frontend): switch to Tailwind v4 tokens — define palette/fonts …
govargas Sep 14, 2025
bf15636
feat(frontend): add accessible Header with brand, menus, language slo…
govargas Sep 14, 2025
f62a468
chore(backend): remove global Mongo connect; connect only in auth/fav…
govargas Sep 14, 2025
e68aaac
chore(backend): harden Mongo connect (fail-fast, no buffer, cached gl…
govargas Sep 14, 2025
c87b2ed
feat(frontend): add haversine distance helper (utils/geo)
govargas Sep 14, 2025
d0ccb79
feat(frontend): add on-demand geolocation hook
govargas Sep 14, 2025
6fe627d
fix(frontend): standardize on lon (keep lng alias) and update feature…
govargas Sep 14, 2025
f3c5c9e
delete tailwind test in App.tsx
govargas Sep 14, 2025
8b3e084
delete tailwind smoke test in main.tsx
govargas Sep 14, 2025
8c7c310
feat(frontend): style BeachesList as cards (custom palette, Spectral …
govargas Sep 14, 2025
de5104f
chore(frontend): keep BeachesList – distance guard & skeletons alread…
govargas Sep 14, 2025
8a931c6
chore(frontend): minor Tailwind component polish (card shadow helper)
govargas Sep 14, 2025
9ea064c
style(frontend): restore v4 @theme tokens and base styles in index.css
govargas Sep 14, 2025
c966aa5
feat(frontend): style Beaches list as cards + proximity pill, skeleto…
govargas Sep 14, 2025
7721fc6
feat(frontend): show water quality + latest rating on Beach detail, a…
govargas Sep 14, 2025
907dd49
chore(frontend): extend BeachDetail with optional sample date fields …
govargas Sep 14, 2025
a65a000
feat(frontend): show latest sample date (Provdatum) on Beach detail w…
govargas Sep 14, 2025
0155e61
chore(frontend): add formatDate util and use browser locale
govargas Sep 14, 2025
acfcad5
feat(frontend): style BeachDetailPage to match mock (quality pill, me…
govargas Sep 15, 2025
1218f27
feat(frontend): add auth token helper (localStorage)
govargas Sep 15, 2025
a718554
feat(frontend): favorites API hooks (list/add/remove) with React Query
govargas Sep 15, 2025
081e152
feat(frontend): wire favorite toggle on BeachDetailPage (prompt for J…
govargas Sep 15, 2025
2b00bbf
feat(frontend): wire Header search input to global store
govargas Sep 15, 2025
d3747a2
feat(frontend): add tiny UI store (zustand) for header search
govargas Sep 15, 2025
adb0eeb
feat(frontend): filter BeachesList via Zustand search (Header input)
govargas Sep 15, 2025
847c1b5
feat(frontend): add UI store (search state) with zustand
govargas Sep 15, 2025
18dd729
feat(backend): add havV2Get helper for HaV v2 API calls
govargas Sep 15, 2025
ede0282
feat(backend): add HaV v2 client + getLatestSampleDate helper; unify …
govargas Sep 15, 2025
51f33f0
feat(backend): include latestSampleDate on /api/beaches/:id using HaV…
govargas Sep 15, 2025
ab35d86
chore(backend): install dotenv for local env loading
govargas Sep 15, 2025
923f404
feat(backend): enrich /api/beaches/:id with latestSampleDate from HaV v2
govargas Sep 15, 2025
e85b6fa
fix(backend): read HaV v2 base from HAV_V2_BASE or HAV_V2_BASE_URL; t…
govargas Sep 15, 2025
521ab56
chore(backend): add request logger and /api/debug/env to troubleshoot…
govargas Sep 15, 2025
1562459
feat(backend): include latestSampleDate on /api/beaches/:id (prefer v…
govargas Sep 15, 2025
f043703
feat(frontend): add short style to formatDate and use for latestSampl…
govargas Sep 15, 2025
d2f9556
chore(frontend): add maplibre-gl (+ types)
govargas Sep 15, 2025
ef6f8f0
style(frontend): import maplibre-gl CSS
govargas Sep 15, 2025
7c0d3e4
feat(frontend): add MapView with MapLibre + MapTiler (compact attribu…
govargas Sep 15, 2025
85277f5
feat(frontend): show MapView above list and wire user location marker
govargas Sep 15, 2025
2c13f99
feat(frontend): square map layout + theme-aware styles and markers
govargas Sep 15, 2025
335eb8d
feat(map): use published MapTiler Customize styles (light/dark) + dar…
govargas Sep 16, 2025
88600d4
feat(map): edit map size
govargas Sep 16, 2025
f1fcf3a
feat(map): use Tailwind classes for markers and keep accent color in …
govargas Sep 16, 2025
36296f7
feat(map): restore edit map size
govargas Sep 16, 2025
f892328
feat(list): limit “near me” to 20 km and pass full filtered set to map
govargas Sep 16, 2025
57b58cf
feat(map+list): default Sergels torg ±20km, fit to radius on “Use loc…
govargas Sep 16, 2025
cf89a9e
feat(map+list): default Sergels torg ±20km, fit to radius on “Use loc…
govargas Sep 16, 2025
9fa11f6
feat(map): adaptive zoom for small radii + no-flicker map init
govargas Sep 17, 2025
7e9a5fe
chore(frontend): remove duplicate LanguageSwitcher under search bar
govargas Sep 17, 2025
ec41549
ui(frontend): move “Use current location” button below map for better…
govargas Sep 17, 2025
b50d78e
ui(frontend): edit BADA title size and weight
govargas Sep 17, 2025
da8499a
ui(frontend): tweak flex alignment of the header text titles
govargas Sep 19, 2025
b699d3a
ui(frontend): replace dummy icons with svg icons for the men
govargas Sep 19, 2025
54c26d2
ui(frontend): install svgr plugin so icons inherit theme colors when …
govargas Sep 19, 2025
8b3afe6
chore: add .env.example files for backend and frontend with safe plac…
govargas Sep 24, 2025
d626463
docs: update README
govargas Sep 24, 2025
cf91ea4
docs: add tech stack and deployment badges to README header
govargas Sep 24, 2025
1f89c66
docs: move README to root
govargas Sep 24, 2025
5e35c12
docs: update README
govargas Sep 24, 2025
015c1fa
update README
govargas Sep 24, 2025
5d088ab
feat(auth): add zustand auth store with localStorage hydration
govargas Sep 24, 2025
d3aa85c
chore: configure @ alias for src in Vite and TypeScript
govargas Sep 24, 2025
bec6c05
refactor(pages): move BeachDetailPage to /src/pages and fix imports
govargas Sep 24, 2025
92fbdb1
feat(pages): add HomePage, LoginPage, RegisterPage, and FavoritesPage…
govargas Sep 24, 2025
704d87c
fix(router): remove nested BrowserRouter from App and keep single rou…
govargas Sep 24, 2025
4a5bad9
feat(api): add apiFetch client with automatic JWT header support and …
govargas Sep 24, 2025
6b64dca
refactor(api): migrate beaches API to apiFetch for consistency with f…
govargas Sep 24, 2025
6399971
chore(api): add optional API request logging controlled by VITE_DEBUG…
govargas Sep 24, 2025
9e552e9
feat(header): integrate auth store and clear React Query cache on logout
govargas Sep 24, 2025
2fd8382
feat(auth): update LoginPage with form validation, error handling, an…
govargas Sep 25, 2025
0e5805b
feat(auth): update RegisterPage with validation and redirect to login
govargas Sep 25, 2025
ddb8cb4
feat(favorites): update protected FavoritesPage with list and remove …
govargas Sep 25, 2025
d023d8c
fix(deps): add react-hook-form, zod, and resolvers to frontend depend…
govargas Sep 25, 2025
976aabf
fix(backend): align start script with server.ts entrypoint
govargas Sep 25, 2025
e7f5000
fix(auth): use auth store in BeachDetailPage and redirect to /login i…
govargas Sep 25, 2025
15513d7
feat(api): add useBeachDetails hook to batch fetch beach details for …
govargas Sep 25, 2025
5fbd85b
feat(favorites): show beach name, municipality and classification on …
govargas Sep 25, 2025
a7304f3
feat(favorites): add friendly empty state with CTA to map
govargas Sep 25, 2025
2aa8718
chore(favorites): show subtle 'updating…' hint while beach details load
govargas Sep 25, 2025
947e417
feat(favorites): add client-side sorting by name or municipality
govargas Sep 25, 2025
56aa68e
chore(deps): add dnd-kit for drag and drop
govargas Sep 25, 2025
472b9b3
feat(favorites): add SortableFavorite component (dnd-kit useSortable)
govargas Sep 26, 2025
f2820bf
feat(favorites): add custom drag-and-drop reordering with dnd-kit and…
govargas Sep 26, 2025
eb44ad7
feat(backend): add field to Favorite model and composite unique index
govargas Sep 26, 2025
59793ad
feat(backend): add PATCH /api/favorites/reorder to persist custom order
govargas Sep 26, 2025
9ad7269
feat(backend): finalize PATCH /favorites/reorder with id de-duplicati…
govargas Sep 26, 2025
4e187c9
feat(api): add useReorderFavorites mutation to persist favorites order
govargas Sep 26, 2025
5c23ef9
feat(favorites): persist custom drag-and-drop order to server on drag…
govargas Sep 26, 2025
7f0b62d
fix(api): subscribe to token in useFavorites and harden apiFetch base…
govargas Sep 26, 2025
0d93b7a
style(favorites): stack title/sort/link on mobile with responsive fle…
govargas Sep 28, 2025
257f68a
feat(netlify): add SPA redirects for Vite in frontend/_redirects
govargas Sep 28, 2025
6e187a1
feat(backend): configure CORS via CORS_ORIGIN env (comma-separated) w…
govargas Sep 28, 2025
ab833cf
feat(backend): add env-driven CORS in index.ts (CORS_ORIGIN with fall…
govargas Sep 28, 2025
8c8be4a
chore: track frontend/package-lock.json for Netlify build
govargas Sep 28, 2025
e0eca22
fix(cors): remove invalid app.options('*') preflight handler causing …
govargas Sep 28, 2025
cf985e0
chore(server): add /api/health endpoint for easy uptime and Mongo check
govargas Sep 28, 2025
4c06241
fix(backend): remove invalid app.options('*') in src/index.ts (Expres…
govargas Sep 28, 2025
da83554
chore(backend): guard & log app.options registrations; dump mounted r…
govargas Sep 28, 2025
c0ee32d
chore(backend): remove temporary route guard
govargas Sep 28, 2025
de30ac4
chore(backend): remove temporary route dump logs
govargas Sep 28, 2025
25ae2e7
chore(backend): remove temporary dumpRoutes callfunction
govargas Sep 28, 2025
91be461
chore(backend): remove legacy server.js entrypoint
govargas Sep 28, 2025
4ad597b
update readme
govargas Sep 28, 2025
0dfc6aa
update readme
govargas Sep 28, 2025
2000b34
chore(backend): expose /api/debug/env before 404 for production diagn…
govargas Sep 28, 2025
41836d3
chore(backend): register /api/debug/env in index.ts before 404; keep …
govargas Sep 28, 2025
290d4e1
fix latest commit
govargas Sep 28, 2025
29ecb55
docs: update README test account to [email protected] (prod-verified)
govargas Sep 28, 2025
60000dc
feat(icons): add light- and dark-mode favicon variants and update ind…
govargas Sep 28, 2025
0da8c38
refactor(router): replace react-router-dom imports with react-router
govargas Oct 10, 2025
3bd3a5a
feat: Add Swedish localization and accessibility improvements
govargas Oct 31, 2025
f110370
docs: Update README
govargas Oct 31, 2025
586494a
feat: Complete Swedish localization and responsive improvements
govargas Oct 31, 2025
8c66ca7
fix: Make search work across all beaches in Sweden
govargas Oct 31, 2025
3bbdcf0
fix: Improve location button behavior and map filtering
govargas Oct 31, 2025
03af0e9
feat: Add clickable links to beach details in map marker popups
govargas Oct 31, 2025
773d561
fix(routing): add SPA redirects and cache external API calls
govargas Nov 2, 2025
dd57d5a
fix: move _redirects to public folder for Netlify SPA routing
govargas Nov 2, 2025
8546daf
fix(header): redirect to home page when searching from non-home pages
govargas Nov 2, 2025
8b5be41
feat(header): add search autocomplete with inline beach results
govargas Nov 2, 2025
ab212a0
fix: achieve 100% Lighthouse scores for accessibility and SEO
govargas Nov 3, 2025
eebf55c
fix: localize water classification badges and remove NUTS code
govargas Nov 3, 2025
028954b
feat: add marker clustering and expand touch targets for accessibility
govargas Nov 3, 2025
e8811a6
fix: increase max zoom level, adjust clustering settings, add smart c…
govargas Nov 3, 2025
7fb0444
fix: contrast improvements for markers
govargas Nov 3, 2025
1ea4889
fix: dark mode beach marker popup contrast
govargas Nov 3, 2025
c4ccd03
fix: language switcher layout fix
govargas Nov 3, 2025
533ec7f
Fix UI and accessibility issues
govargas Nov 27, 2025
c06cd7c
Remove dist folders from version control
govargas Nov 27, 2025
b1c7fcb
feat: enhance header and language switcher UI, add algal status and E…
govargas Nov 27, 2025
b0a6656
feat: enhance beach detail and classification tooltips
govargas Nov 27, 2025
2356ee5
feat: update UI with ambient backgrounds and enhance styling
govargas Dec 4, 2025
155eb2e
refactor: update sand and water shader properties for improved visual…
govargas Dec 4, 2025
6491d3f
fix: update sand color for improved visual consistency in shader
govargas Dec 7, 2025
4b20c53
refactor: enhance sand and water shader for improved visual effects
govargas Dec 7, 2025
98ab57d
style: enhance glassmorphism header with improved gradients and depth…
govargas Dec 8, 2025
37cf9b0
feat: update font styles in header and CSS for improved typography
govargas Dec 8, 2025
2b2ba88
style: refine ambient background CSS for improved visual consistency
govargas Dec 8, 2025
19f43d3
feat: update font usage across components for enhanced typography
govargas Dec 8, 2025
a626446
style: update font weight for beach link in SortableFavorite component
govargas Dec 8, 2025
9f9c40b
style: update font references and improve spacing in BeachesList comp…
govargas Dec 8, 2025
ec43c82
feat: enhance README and improve accessibility features
govargas Dec 8, 2025
7bde94a
style: update accent color and improve code formatting in MapView com…
govargas Dec 8, 2025
5eb4138
refactor: streamline cluster expansion logic in MapView component
govargas Feb 10, 2026
d1dfe64
fix: reduce Three.js shader contrast and increase glass opacity for b…
govargas Apr 20, 2026
9986859
fix: correct package name and remove duplicate dependency in frontend
govargas Jun 6, 2026
d30c6ba
refactor: move useOutsideClose and usePrefersReducedMotion to /hooks
govargas Jun 6, 2026
585d993
refactor: extract useDarkMode variants to dedicated hooks files
govargas Jun 6, 2026
90077c2
feat: add weather and sun times data layer
govargas Jun 8, 2026
cc7b7e1
feat: add weather and sun times UI to beach detail page
govargas Jun 8, 2026
939a2b5
fix: improve sun arc bar — darker golden hour label, edge-clamped lab…
govargas Jun 8, 2026
c8cf093
Merge pull request #1 from govargas/feature/weather-sun-data-layer
govargas Jun 8, 2026
c630346
fix: improve contrast of golden hour label in light theme
govargas Jun 8, 2026
4e21992
docs: update README with weather/sun feature and hook refactors
govargas Jun 8, 2026
2e8edcf
fix: remove /api/debug/env endpoint leaking config in production
govargas Jun 10, 2026
3191ecf
fix: add 5s timeout to HaV calls and cache beach list for 1h
govargas Jun 10, 2026
eecb897
fix: read MapTiler key from env instead of hardcoding it
govargas Jun 10, 2026
16ea76e
fix: remove self-reinforcing refetch loop in BeachesList
govargas Jun 10, 2026
1bc75e8
fix: drop raw lat/lon from beach list cards
govargas Jun 10, 2026
ded0b4c
fix: stop re-binding map handlers and rebuilding source on every pan
govargas Jun 10, 2026
ae665ae
feat: add 5-day forecast to the beach weather panel
govargas Jun 10, 2026
5bdd523
feat: surface swimming advisories (dissuasion) on beach detail
govargas Jun 10, 2026
dd8e38d
fix(a11y): proper combobox for search; drop invalid menu roles
govargas Jun 10, 2026
905578d
perf: serve beach list from a static CDN snapshot, refreshed daily
govargas Jun 10, 2026
3b89237
feat: per-beach document.title and generated sitemap for SEO
govargas Jun 10, 2026
122f122
perf: split maplibre-gl into its own chunk
govargas Jun 10, 2026
82c8ffe
docs: add Known Limitations section and scope the a11y claim
govargas Jun 10, 2026
d127bd9
Merge pull request #2 from govargas/fix/pre-mortem-hardening
govargas Jun 10, 2026
208cf36
fix: show '—' instead of raw 'false' for empty EU motive and algal text
govargas Jun 10, 2026
08cfe9e
fix(a11y): meet WCAG AA contrast for quality/UV colors; add home h1
govargas Jun 10, 2026
27bb20b
chore: refresh beaches snapshot
github-actions[bot] Jun 12, 2026
49e7b28
chore: gitignore local .claude/ and .skills/ dirs
govargas Jun 12, 2026
d37c9cd
feat(design): elevate glass system, consolidate type, fix dark-mode c…
govargas Jun 12, 2026
c91b1c8
chore: refresh beaches snapshot
github-actions[bot] Jun 13, 2026
b128cd2
chore: refresh beaches snapshot
github-actions[bot] Jun 16, 2026
236cd2c
fix(ci): retry transient HaV errors; bump actions to node24
govargas Jun 28, 2026
16326df
feat(beach-detail): add swim-safety verdict and info tooltip to algal…
govargas Jun 28, 2026
f58b16c
feat(background): richer dark-theme water shader; throttle background…
govargas Jun 28, 2026
ad2bc20
security: harden backend, sanitize map popups, track lockfile
govargas Jun 28, 2026
f8215b7
refactor(backend): mount favorites router at /api/favorites
govargas Jun 28, 2026
b25d164
test(backend): add favorites API smoke-test script
govargas Jun 28, 2026
6468c52
fix(frontend): never run API debug logging in deployed builds
govargas Jun 28, 2026
2562c12
feat(beach-detail): add swim-safety disclaimer with data-freshness note
govargas Jun 28, 2026
e56cfb9
feat: add privacy policy and account deletion (GDPR)
govargas Jun 28, 2026
738c43a
test(backend): add auth + favorites test suite and CI
govargas Jun 28, 2026
8e8fd63
feat(backend): shared-store auth rate limiting via Upstash Redis
govargas Jun 28, 2026
1bfe3d8
chore: remove dead auth util and stray root deps
govargas Jun 29, 2026
52f073e
spike: temporary cookie-topology probe via Netlify proxy
govargas Jun 29, 2026
a67613a
spike: dump all request headers to hunt for client IP through proxy
govargas Jun 29, 2026
7075bac
spike: remove cookie-topology probe
govargas Jun 29, 2026
41d10a2
feat(backend): httpOnly session cookie auth with header fallback
govargas Jun 29, 2026
1af0025
fix(backend): rate-limit on Netlify-forwarded client IP
govargas Jun 29, 2026
298ad4c
feat(frontend): cookie session auth via Netlify proxy (topology A)
govargas Jun 29, 2026
baa477c
feat(backend): verify Netlify proxy signature for rate-limit IP trust
govargas Jun 29, 2026
b97f4d0
chore: activate signed Netlify proxy + temp signing diagnostic
govargas Jun 29, 2026
5a9bc69
chore(temp): marker header to detect netlify.toml base dir
govargas Jun 29, 2026
c305f85
chore(temp): drop unsigned /api fallback from _redirects so signed ru…
govargas Jun 29, 2026
b2dac95
fix: restore /api proxy fallback (signed netlify.toml rule not applying)
govargas Jun 29, 2026
e2be412
chore(temp): isolate netlify.toml plain vs signed proxy behavior
govargas Jun 29, 2026
971fe59
fix(netlify): consolidate routing into netlify.toml, drop _redirects
govargas Jun 29, 2026
a934938
chore: remove temp proxy-signing diagnostics
govargas Jun 29, 2026
d82ea79
Improve beach weather forecast UI
govargas Jun 29, 2026
105dde7
Harden WebGL fallbacks
govargas Jun 29, 2026
5fab4c8
Refine beach detail summary
govargas Jun 29, 2026
262de26
Polish sun times panel
govargas Jun 29, 2026
9339a11
Tighten beach detail layout
govargas Jun 29, 2026
932a7dd
chore: refresh beaches snapshot
github-actions[bot] Jun 30, 2026
08679f5
Polish BADA interface
govargas Jun 30, 2026
7adc659
Fix map state and theme defaults
govargas Jun 30, 2026
3e6efd5
chore: refresh beaches snapshot
github-actions[bot] Jul 1, 2026
0d3c342
chore: refresh beaches snapshot
github-actions[bot] Jul 2, 2026
6572e7d
Fix crash on beaches with swimming advisory
govargas Jul 2, 2026
f083432
Unify quality classification mapping
govargas Jul 2, 2026
24d9ee2
Resolve algae advisory vs. sample contradiction
govargas Jul 2, 2026
8165b04
fix backend auth and API errors
govargas Jul 3, 2026
78907a7
fix frontend interaction bugs
govargas Jul 3, 2026
f424243
remove bearer auth fallback
govargas Jul 3, 2026
4e31e95
remove stale project artifacts
govargas Jul 3, 2026
bc9539a
fix docs and config drift
govargas Jul 3, 2026
cb2f974
chore: refresh beaches snapshot and sitemap
github-actions[bot] Jul 4, 2026
8d746c8
chore: refresh beaches snapshot and sitemap
github-actions[bot] Jul 5, 2026
5d53941
chore: refresh beaches snapshot and sitemap
github-actions[bot] Jul 6, 2026
3d81c73
chore: refresh beaches snapshot and sitemap
github-actions[bot] Jul 7, 2026
ae00023
chore: refresh beaches snapshot and sitemap
github-actions[bot] Jul 8, 2026
d9ee937
chore: refresh beaches snapshot and sitemap
github-actions[bot] Jul 9, 2026
2616f15
chore: refresh beaches snapshot and sitemap
github-actions[bot] Jul 10, 2026
e0f1678
rework dark-mode water shader with analytic waves, require WebGL2
govargas Jul 10, 2026
75a51b2
darken water palette slightly
govargas Jul 10, 2026
33d818b
feat: add swim-safety nowcast to beach detail page
govargas Jul 10, 2026
a59852f
test: add Vitest suite for swim-forecast scoring
govargas Jul 10, 2026
e0ac0d2
fix: resolve swim-forecast coordinates from the beach list
govargas Jul 10, 2026
c1d8d56
fix(backend): load env before app modules evaluate
govargas Jul 10, 2026
6ad3e38
feat(forecast): add wind and wave signals; put today's verdict front …
govargas Jul 10, 2026
d9b0cfc
feat(backend): run the Express API as a Netlify Function
govargas Jul 10, 2026
1149eb4
feat(watch): beach watch notifications, free for everyone
govargas Jul 10, 2026
2439ed5
feat: rebrand BADA → Badlistan
govargas Jul 10, 2026
6db8b37
chore(dev): proxy /api to the local backend in vite dev
govargas Jul 10, 2026
0fe3daf
fix(functions): default NODE_ENV=production in the api function
govargas Jul 10, 2026
d62bfb8
chore: ignore local .netlify folder
govargas Jul 10, 2026
1dc802c
fix(build): make the Netlify build work under npm 10
govargas Jul 10, 2026
4363917
fix(functions): default NETLIFY=true in the api function runtime
govargas Jul 10, 2026
653ed6a
style(background): darken the water shader palette slightly
govargas Jul 10, 2026
0b7cf8e
fix(backend): satisfy strict typecheck in the watch notifier
govargas Jul 11, 2026
245017c
fix(build): deploy on backend-only commits too
govargas Jul 11, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 58 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
name: CI

on:
push:
branches: [main]
pull_request:

permissions:
contents: read

jobs:
backend:
name: Backend (typecheck + tests)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5

- uses: actions/setup-node@v5
with:
node-version: 24
cache: npm
cache-dependency-path: backend/package-lock.json

- name: Install
run: npm ci
working-directory: backend

- name: Typecheck
run: npx tsc --noEmit
working-directory: backend

- name: Test
run: npm test
working-directory: backend

frontend:
name: Frontend (typecheck + build)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5

- uses: actions/setup-node@v5
with:
node-version: 24
cache: npm
cache-dependency-path: frontend/package-lock.json

- name: Install
run: npm ci
working-directory: frontend

- name: Typecheck
run: npx tsc --noEmit
working-directory: frontend

- name: Build
run: npx vite build
working-directory: frontend
38 changes: 38 additions & 0 deletions .github/workflows/refresh-beaches.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
name: Refresh beaches snapshot

# The beach list changes only a few times a year, so a daily refresh of the
# static snapshot (frontend/public/beaches.json) is plenty. Runs on a schedule
# and on demand; commits only when the data or sitemap actually changed.

on:
schedule:
- cron: "0 4 * * *" # daily at 04:00 UTC
workflow_dispatch:

permissions:
contents: write

jobs:
refresh:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5

- uses: actions/setup-node@v5
with:
node-version: 24

- name: Build snapshot
run: node scripts/build-beaches.mjs

- name: Commit if changed
run: |
if [[ -n "$(git status --porcelain frontend/public/beaches.json frontend/public/sitemap.xml)" ]]; then
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git add frontend/public/beaches.json frontend/public/sitemap.xml
git commit -m "chore: refresh beaches snapshot and sitemap"
git push
else
echo "Snapshot and sitemap unchanged — nothing to commit."
fi
11 changes: 10 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,18 @@ node_modules
.env.production.local

build
dist

npm-debug.log*
yarn-debug.log*
yarn-error.log*

package-lock.json
package-lock.json
!frontend/package-lock.json
!backend/package-lock.json

CLAUDE.md
.claude/
.skills/
# Local Netlify folder
.netlify
1 change: 0 additions & 1 deletion Procfile

This file was deleted.

242 changes: 235 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,241 @@
# Final Project
# 🏖️ Badlistan – Koll på badvattnet i hela Sverige

Replace this readme with your own information about your project.
![React](https://img.shields.io/badge/Frontend-React_18-61DAFB?logo=react&logoColor=white)
![Express](https://img.shields.io/badge/Backend-Express_5-000000?logo=express&logoColor=white)
![MongoDB](https://img.shields.io/badge/Database-MongoDB-47A248?logo=mongodb&logoColor=white)
![TypeScript](https://img.shields.io/badge/Code-TypeScript-3178C6?logo=typescript&logoColor=white)
![TailwindCSS](https://img.shields.io/badge/UI-Tailwind_CSS_v4-38B2AC?logo=tailwind-css&logoColor=white)
![Three.js](https://img.shields.io/badge/3D-Three.js-000000?logo=three.js&logoColor=white)
![MapLibre](https://img.shields.io/badge/Maps-MapLibre-4264FB?logo=openstreetmap&logoColor=white)
![i18next](https://img.shields.io/badge/Translations-i18next-26A69A?logo=i18next&logoColor=white)
![TanStack Query](https://img.shields.io/badge/State-TanStack_Query-FF4154?logo=reactquery&logoColor=white)
![Deployed](https://img.shields.io/badge/Deployed-Netlify-00C7B7?logo=netlify&logoColor=white)

Start by briefly describing the assignment in a sentence or two. Keep it short and to the point.
**Badlistan** helps beachgoers and families in Sweden find safe, EU-classified bathing waters with real-time quality updates.
It replaces outdated or clunky websites with a **clean, mobile-friendly experience** where you can browse nearby beaches on a map, check water quality, and save your favourites.

## The problem
[Try it out here](https://badaweb.netlify.app/) (deployed on Netlify)

Describe how you approached to problem, and what tools and techniques you used to solve it. How did you plan? What technologies did you use? If you had more time, what would be next?
---

## View it live
## ✨ Features

Every project should be deployed somewhere. Be sure to include the link to the deployed project so that the viewer can click around and see what it's all about.
- 🗺 **Map of all EU-classified beaches in Sweden** (MapLibre + OpenStreetMap)
- 📍 **Find the nearest beach** using your device's location
- 🔬 **View water quality, classification, and recent test results** (data from HaV)
- 🔍 **Real-time beach search** with autocomplete dropdown
- ❤️ **Create an account and save favourite beaches** to your profile
- 🔀 **Custom sorting for favorites** with pointer and keyboard controls
- 🌊 **3D animated backgrounds** (WebGL water simulation in dark mode, sand texture in light mode)
- 🎨 **Glassmorphism UI** with backdrop blur effects
- 🌤️ **Weather & sun times panel** on each beach — air temp, feels like, UV index, water temperature, and a visual sun arc with golden hour, sunrise/sunset, and twilight phases
- 🌗 **Dark mode** and responsive design (mobile → desktop)
- 🌐 **Multi-language support** (Swedish / English)
- 📚 **API Documentation** (Swagger UI at `/api/docs`)

---

## 🚀 Tech Stack

**Frontend**

- React 18 + Vite + TypeScript
- React Router v7
- Zustand (global state)
- TanStack Query (server state & caching)
- Tailwind CSS v4 (with CSS-based theme system)
- i18next (translations)
- MapLibre GL (maps)
- Three.js ecosystem (@react-three/fiber, @react-three/drei) for 3D backgrounds
- @dnd-kit (drag-and-drop)
- react-hook-form + Zod (form validation)
- react-hot-toast (notifications)

**Custom React Hooks**

- `useGeolocation` – Device location access
- `useOutsideClose` – Close popovers on outside click/Escape key
- `useToggleDarkMode` – Writes the `.dark` class (used in Header)
- `useDarkModeObserver` – Reads/observes `.dark` class via MutationObserver (used in AmbientBackground)
- `usePrefersReducedMotion` – Respect user's motion preferences
- `useBeaches` – Beach data fetching
- `useWeather` – Weather data with 30-min stale time
- `useSunTimes` – Sun times keyed by date with 12-hr stale time

**Backend**

- Node.js + Express 5
- MongoDB + Mongoose
- Cookie-based JWT sessions
- Zod (validation)
- In-memory caching for HaV API responses
- Swagger UI (API documentation)

**External APIs**

- [HaV Bathing Waters API](https://badplatsen.havochvatten.se/) (official Swedish Agency for Marine and Water Management)
- [MapTiler](https://www.maptiler.com/) (map styles)
- [Open-Meteo](https://open-meteo.com/) (weather forecast + marine/water temperature)
- [sunrise-sunset.org](https://sunrise-sunset.org/api) (sunrise, sunset, golden hour, and twilight times)

---

## ♿ Accessibility

Badlistan is built with accessibility in mind:

- **Skip navigation link** – Jump directly to main content
- **ARIA labels** – Proper labeling of interactive elements
- **ARIA live regions** – Screen reader announcements for dynamic content
- **ARIA busy states** – Loading indicators for assistive technology
- **Keyboard navigation** – Search is an ARIA combobox (arrow keys / Enter / Escape); menus, dialogs, and favorite reordering are keyboard-operable with focus management
- **Escape key handling** – Close menus and return focus to trigger
- **Focus visible rings** – Clear focus indicators
- **Reduced motion support** – Respects `prefers-reduced-motion` (both CSS and JS)
- **Semantic HTML** – Proper document structure with roles
- **Dynamic lang attribute** – HTML lang updates with language selection
- **Accessible notifications** – Toast messages with proper ARIA live regions

---

## 📸 Screenshots

_(Coming soon)_

---

## 🛠 Installation & Setup

Clone the repo and install dependencies:

```bash
git clone https://github.com/govargas/bada.git
cd bada
```

**Backend**

```bash
cd backend
cp .env.example .env.local # then fill in your values
npm install
npm run dev
```

Backend runs on http://localhost:3000

API Documentation available at http://localhost:3000/api/docs

Raw OpenAPI JSON is available at http://localhost:3000/api/docs/openapi.json

**Frontend**

```bash
cd frontend
cp .env.example .env.local # then fill in your values
npm install
npm run dev
```

Frontend runs on http://localhost:5173

---

## 🔑 Environment Variables

- See .env.example in both backend/ and frontend/.
- Fill in with your own values (MongoDB Atlas, JWT secret, MapTiler key).

---

## 🌍 Deployment

- Frontend: Deployed on Netlify: https://badaweb.netlify.app/
- Backend: Deployed on Vercel → https://bada-backend.vercel.app/api/health

---

## ✅ Requirements Checklist

### Technical Requirements (Grade G)

- ✅ React frontend
- ✅ Node.js + Express backend
- ✅ MongoDB database
- ✅ Authentication (httpOnly cookie session with JWT)
- ✅ React Router navigation
- ✅ Global state management (Zustand)
- ✅ ≥2 external libraries (TanStack Query, MapLibre, Three.js, react-hook-form, i18next, react-hot-toast, @dnd-kit)
- ✅ Custom React hooks (useGeolocation, useOutsideClose, useToggleDarkMode, useDarkModeObserver, usePrefersReducedMotion, useBeaches, useWeather, useSunTimes)
- ✅ Responsive (320px → 1600px+)
- ✅ Accessibility features (comprehensive a11y implementation)
- ✅ Clean Code practices

### Visual Requirements

- ✅ Clear structure using box model with consistent margins/paddings
- ✅ Consistent typography across views and breakpoints
- ✅ Cohesive color scheme with CSS design tokens
- ✅ Mobile-first responsive design
- ✅ Dark mode support with 3D backgrounds
- ✅ Multi-language support (Swedish/English)
- ✅ Glassmorphism UI design system

### Grade VG Enhancements

- ✅ Error Boundaries
- ✅ Toast notifications with a11y
- ✅ Reduced motion support
- ✅ Comprehensive documentation
- ✅ Meta tags for SEO (Open Graph, Twitter Cards)
- ✅ API Documentation (Swagger UI)
- ✅ Performance optimizations (lazy-loaded 3D backgrounds)

---

## ⚠️ Known Limitations

These are conscious trade-offs for an MVP, documented rather than hidden:

- **Backend cache is per-instance.** The HaV proxy cache is an in-memory `Map`. On Vercel serverless it does not survive cold starts or span instances, so it mainly de-dupes bursts within a warm instance. The beach _list_ sidesteps this entirely via a static CDN snapshot (`frontend/public/beaches.json`, refreshed daily by a GitHub Action); only per-beach detail still hits the proxy.
- **Data is seasonal.** HaV samples bathing waters roughly June–August. Outside the season `latestSampleDate` and classification reflect the previous year.
- **Golden hour is approximate.** It is computed as sunrise + 1h / sunset − 1h, and the sun arc degrades north of the Arctic Circle during the midnight sun (sunrise-sunset.org returns degenerate times there).
- **Third-party APIs called from the client.** Open-Meteo and sunrise-sunset.org are called directly from the browser with no SLA — acceptable for an MVP, not for production traffic.
- **Session cookie auth.** Login sets an httpOnly `bada_session` cookie through the Netlify `/api/*` proxy so the session stays first-party and unavailable to JavaScript.
- **No SSR.** SEO is limited to per-route `<title>`, a generated `sitemap.xml`, and site-wide Open Graph tags. Per-beach Open Graph previews would require prerendering.

---

## 🧭 Roadmap

### Completed

- ✅ 3D animated backgrounds (WebGL water/sand)
- ✅ Enhanced glassmorphism UI
- ✅ Header search with autocomplete
- ✅ Comprehensive accessibility implementation
- ✅ API documentation with Swagger
- ✅ Performance optimization (deferred 3D loading)
- ✅ Focus management and keyboard navigation
- ✅ Weather & sun times panel (Open-Meteo + sunrise-sunset.org) with visual sun arc, golden hour zones, and water temperature

### Planned

- 🔄 Filter beaches by classification
- 🔄 Add user beach photos
- 🔄 Allow notes/tips per beach (e.g. "good for kids")
- 🔄 PWA support with offline capability

---

## 💡 Inspiration & Credits

- Data from the Swedish Agency for Marine and Water Management (HaV)
- Maps powered by OpenStreetMap + MapTiler
- Built during the Technigo Fullstack JavaScript Bootcamp (2025)

---

## 👨‍💻 Author

Created by Talo Vargas, 2025
5 changes: 0 additions & 5 deletions backend/.babelrc

This file was deleted.

Loading