Frontend: Publika sidor
🌐hittadittsverige.se
Nationell startsida. Kommunkort, karta, exploration entry points.
Static HTML
🏛pitea.hittadittsverige.se
Kommunportal. Branding via _applyCommuneBranding(). loadCommune() API-call vid init.
HTML+JSAPI
📄commune-subpage.html
Generisk mall för kommunens undersidor (mat, boende, aktiviteter, gemenskap, karta, rutter m.fl.). Läser page_slug från URL. Renderar blocks från API.
Templateblocks.php
📝artiklar/ · artikel/
Kommunartikellistning med kategorifilter. Detaljsida med breadcrumb och body HTML.
editorial/list.php
❓hjalp/ · hjalp/artikel/
Kunskapsbas med sökning, kategorigrid och artikelrendering. Feedback i localStorage.
articles.json
Backend: API-lager
🔐_helpers.php
hds_require_auth(), hds_require_entity_access(), hds_audit(), hds_db(), hds_ok/err(). Kärna för all API-logik.
Auth corePDO
🏛commune/settings.php
GET/PATCH kommunens varumärke, navigation, kontakt.
GET PATCH
📦commune/blocks.php → profile/pages.php
blocks.php är numera en kompatibilitetsshim (endast GET) som vidarebefordrar till den generaliserade profile/pages.php. 11 blocktyper validerade mot profile_page_blocks.
GET (shim) · POST/PATCH/DELETE via profile/pages.php
👥commune/users.php
GET team, PATCH roll (inkl. village_admin + village_id), DELETE user. Joins village_admins.
GET PATCH DELETE
📝editorial/ (save, list, delete)
CRUD artiklar. Non-admin scoped till hds_managed_komkod. Kategorifilter i list.php.
POST GET DELETE
📷upload/ (commune-image, entity)
Magic-byte validering, GD resize 2000px, max 20 per kommun. Public GET utan auth.
POST GET DELETE
🏠village/details.php
Byprofil: GET sammanfogar villages.json + village_overrides. PATCH upserts overrides.
GET PATCHvillage_overrides
📋commune/audit-log.php
Returnerar senaste 50 loggposter för alla konton kopplade till kommunen.
GETaudit_log
Dashboard och data
🔧dashboard/index.html
SPA-liknande dashboard. ROLE_CONFIG mappar roller till flikar. Alla administrativa funktioner.
~2800 rader
📊ROLE_CONFIG objekt
admin, commune_coordinator, tourism_board, rural_dev, field_agent, village_admin, forening, business, member_local, member_tourist
10 roller
🗃data/entities.json
510+ entiteter. Statisk fil, läses direkt av frontend. Källa för entity_commune-tabell.
JSON statisk
🏠data/villages.json
Byar med namn, koordinater, taxonomy. Bas för village/details.php.
JSON statisk
🗺data/ routes (GPX, JSON)
Cykelleder, vandringsleder, semesterrutter. Visas på karta och i rutter-katalogen.
GPX + JSON
⚡APCu in-process cache
entities/browse.php cachar verifierade sökresultat i PHP-process. TTL 60 sekunder.
In-memory
Viktiga dataflöden
Browser
→
pitea.hittadittsverige.se
→
loadCommune()
→
commune/settings.php
→
MySQL communes
Branding load
commune-subpage.html
→
commune/blocks.php?page_slug=X
→
profile_page_blocks
→
renderBlock(type, data)
Block rendering per page slug
Dashboard (coordinator)
→
commune/invite.php
→
accounts INSERT
→
_mailer.php → SMTP
Team invitation flow
Fältagent (app)
→
entities/update.php
→
hds_require_entity_access()
→
entity_commune lookup
Access grant: field_agent via entity_commune table
village_admin
→
hds_entity_id = village_id
→
entity.village == hds_entity_id
Village admin scoping via session entity_id field
Databastabeller: kommunvertikalen
accounts
- id (PK)
- display_name
- email
- role (ENUM)
- managed_komkod
- entity_id (village_id)
- active TINYINT
communes
- komkod (PK)
- display_name
- tagline
- accent_color
- logo_url
- banner_url
profile_pages
- id (PK)
- profile_id
- profile_type ENUM(entity,commune,village,area)
- slug
- published TINYINT
- sort_order INT
profile_page_blocks
- id (PK)
- profile_id
- profile_type ENUM
- page_slug
- type (ENUM 11)
- sort_order INT
- data JSON
editorial_posts
- id (PK)
- slug (UNIQUE)
- commune_id (nullable)
- category
- status ENUM
- featured TINYINT
- publish_at DATETIME
entity_commune
- entity_id (PK)
- commune_id
- /* rader härledda från entities.json */
village_admins
- id (PK)
- account_id
- village_id
- created_at
village_overrides
- village_id (PK)
- data JSON
- tagline
- description TEXT
- image_url
- tabs_config JSON
- updated_at / updated_by
audit_log
- id (PK)
- account_id
- action VARCHAR
- entity_id
- ip_hash
- created_at
entity_overrides
- entity_id (PK)
- data JSON
- verified TINYINT
- verified_at
- verified_certifications JSON
- updated_at / updated_by
entity_media
- id (PK)
- entity_id
- file_path
- media_type ENUM(photo,logo,cover)
- caption
- sort_order
entity_contact_messages
- id (PK)
- entity_id
- sender_name
- sender_email
- message TEXT
- read_at DATETIME
- created_at
Obs: commune_settings, commune_page_blocks, entity_blocks, entity_branding, entity_seo_meta, contact_messages och gallery_albums från en tidigare version av detta dokument existerar inte längre — ersättes av profile_pages/profile_page_blocks (migration 108), entity_overrides, entity_media och entity_contact_messages ovan.
Frontend: Public Pages
🌐hittadittsverige.se
National homepage. Municipality cards, map, exploration entry points.
Static HTML
🏛pitea.hittadittsverige.se
Municipality portal. Branding via _applyCommuneBranding(). loadCommune() API call on init.
HTML+JSAPI
📄commune-subpage.html
Generic template for the municipality's sub-pages (food, lodging, activities, community, map, routes, etc). Reads page_slug from URL. Renders blocks from API.
Templateblocks.php
📝artiklar/ · artikel/
Municipality article listing with category filter. Detail page with breadcrumb and body HTML.
editorial/list.php
❓hjalp/ · hjalp/artikel/
Knowledge base with search, category grid, and article rendering. Feedback in localStorage.
articles.json
Backend: API Layer
🔐_helpers.php
hds_require_auth(), hds_require_entity_access(), hds_audit(), hds_db(), hds_ok/err(). Core for all API logic.
Auth corePDO
🏛commune/settings.php
GET/PATCH municipality brand, navigation, contact.
GET PATCH
📦commune/blocks.php → profile/pages.php
blocks.php is now a GET-only compatibility shim that forwards to the generalized profile/pages.php. 11 block types validated against profile_page_blocks.
GET (shim) · POST/PATCH/DELETE via profile/pages.php
👥commune/users.php
GET team, PATCH role (incl. village_admin + village_id), DELETE user. Joins village_admins.
GET PATCH DELETE
📝editorial/ (save, list, delete)
CRUD articles. Non-admin scoped to hds_managed_komkod. Category filter in list.php.
POST GET DELETE
📷upload/ (commune-image, entity)
Magic-byte validation, GD resize 2000px, max 20 per municipality. Public GET without auth.
POST GET DELETE
🏠village/details.php
Village profile: GET merges villages.json + village_overrides. PATCH upserts overrides.
GET PATCHvillage_overrides
📋commune/audit-log.php
Returns the last 50 log entries for all accounts linked to the municipality.
GETaudit_log
Dashboard and Data
🔧dashboard/index.html
SPA-style dashboard. ROLE_CONFIG maps roles to tabs. All administrative functions.
~2800 lines
📊ROLE_CONFIG object
admin, commune_coordinator, tourism_board, rural_dev, field_agent, village_admin, forening, business, member_local, member_tourist
10 roles
🗃data/entities.json
510+ entities. Static file, read directly by frontend. Source for entity_commune table.
JSON static
🏠data/villages.json
Villages with name, coordinates, taxonomy. Base for village/details.php.
JSON static
🗺data/ routes (GPX, JSON)
Cycling trails, hiking routes, holiday routes. Shown on map and in routes catalogue.
GPX + JSON
⚡APCu in-process cache
entities/browse.php caches verified search results in the PHP process. TTL 60 seconds.
In-memory
Key Data Flows
Browser
→
pitea.hittadittsverige.se
→
loadCommune()
→
commune/settings.php
→
MySQL communes
Branding load
commune-subpage.html
→
commune/blocks.php?page_slug=X
→
profile_page_blocks
→
renderBlock(type, data)
Block rendering per page slug
Dashboard (coordinator)
→
commune/invite.php
→
accounts INSERT
→
_mailer.php → SMTP
Team invitation flow
Field Agent (app)
→
entities/update.php
→
hds_require_entity_access()
→
entity_commune lookup
Access grant: field_agent via entity_commune table
village_admin
→
hds_entity_id = village_id
→
entity.village == hds_entity_id
Village admin scoping via session entity_id field
Database Tables: the municipal vertical
accounts
- id (PK)
- display_name
- email
- role (ENUM)
- managed_komkod
- entity_id (village_id)
- active TINYINT
communes
- komkod (PK)
- display_name
- tagline
- accent_color
- logo_url
- banner_url
profile_pages
- id (PK)
- profile_id
- profile_type ENUM(entity,commune,village,area)
- slug
- published TINYINT
- sort_order INT
profile_page_blocks
- id (PK)
- profile_id
- profile_type ENUM
- page_slug
- type (ENUM 11)
- sort_order INT
- data JSON
editorial_posts
- id (PK)
- slug (UNIQUE)
- commune_id (nullable)
- category
- status ENUM
- featured TINYINT
- publish_at DATETIME
entity_commune
- entity_id (PK)
- commune_id
- /* rows derived from entities.json */
village_admins
- id (PK)
- account_id
- village_id
- created_at
village_overrides
- village_id (PK)
- data JSON
- tagline
- description TEXT
- image_url
- tabs_config JSON
- updated_at / updated_by
audit_log
- id (PK)
- account_id
- action VARCHAR
- entity_id
- ip_hash
- created_at
entity_overrides
- entity_id (PK)
- data JSON
- verified TINYINT
- verified_at
- verified_certifications JSON
- updated_at / updated_by
entity_media
- id (PK)
- entity_id
- file_path
- media_type ENUM(photo,logo,cover)
- caption
- sort_order
entity_contact_messages
- id (PK)
- entity_id
- sender_name
- sender_email
- message TEXT
- read_at DATETIME
- created_at
Note: commune_settings, commune_page_blocks, entity_blocks, entity_branding, entity_seo_meta, contact_messages and gallery_albums from an earlier version of this document no longer exist — superseded by profile_pages/profile_page_blocks (migration 108), entity_overrides, entity_media and entity_contact_messages above.