PK Spot (pkspot.app)
The spot for everything parkour.
Find spots, check in, discover what is happening nearby, and connect with your local Parkour community.
PK Spot is growing toward one app for Parkour spots, training, events, jams, and community.
- Added notifications to iOS, Android, and Web: community digests, event reminders, and Spot edit submission updates
- Added Google Weather to Spots, the current map area, and events
- Improved Events: RSVP became "Add to My Events" and enables notifications
- Updated Profile pages and following mechanics
- Users can submit community card suggestions
- Moderation queue for admins to view community and spot votes
- Event info pages
- Community info cards
- Event series to filter by
- Map performance and UI/UX improvements
- Organizations can verify spots
- Event RSVPs
- Bug fixes and polishing
- Added Communities and Events
- Save spots and mark them as visited
- Added community pages and map search
- Bug fixes and UI polish
- Added saved and visited spot lists
- Improved provenance and verification workflows
- Bug fixes and more
- Performance and image-loading improvements
- Added the hybrid satellite map with location labels
- Added splash screens and animated spot previews
- Fixed spot image editing side effects and mobile splash screens
- Improved map performance and location UX
- Improved spot previews, highlights, and clusters
- Added Android early access setup
- Fixed Google sign-in on some devices with browser redirect fallback
- Fixed profile picture uploads, media ordering, and language startup issues
Contributions are welcome. To collaborate on the codebase:
- Fork this repository.
- Create a focused branch for your change.
- Follow the local setup below.
- Run the relevant tests before submitting.
- Open a pull request on GitHub.
Keep changes small and focused where possible. For code changes, prefer existing Angular and Firebase patterns in the project over introducing new abstractions.
For bug reports, please open an issue in this GitHub repository. You can also reach out on Instagram, Discord, or by email at contact@lukasbuehler.ch.
For feature requests, please use Discord or contact me directly.
To setup for local development, duplicate the file src/environments/environment.default.ts to src/environments/environment.development.ts.
Replace the firebaseConfig with your own from Firebase.
Under keys.firebaseConfig.apiKey you will need to add your own Google API Key, with the following APIs enabled for full functionality:
- Firebase App Check API
- IAM Service Account Credentials
- Identity and Access Management (IAM) API
- Identity Toolkit API
- Maps JavaScript API
- Places API (New)
- Secret Manager API
- Street View Static API
- Token Service API
- FCM Registration API
- Firebase Installations API
You will need a different Google API Key that you pass as a secret to your
Firebase cloud functions as GOOGLE_API_KEY.
It needs the following APIs enabled:
- Geocoding API (reverse geocoding for addresses)
- Cloud Vision API (for automated image content checking)
- Weather API (for weather)
The translation files are in src/locale and
English (en) is the source language.
To tweak a translation, go to the corresponding file, find the string you want to change, and update the value inside the target XML tag only. Example:
<xliff version="2.0" xmlns="urn:oasis:names:tc:xliff:document:2.0" srcLang="en" trgLang="de">
<file id="ngi18n" original="ng.template">
<unit id="1940752772695642659">
<segment state="initial">
<source> The spot for everything parkour. </source>
<target> Der Spot für alles rund um Parkour. </target>
</segment>
</unit>
...
</file>
</xliff>After adding new text in the HTML markup and adding the i18n attribute, update the language files so they include the new source text.
Run the following command:
npm run ng -- extract-i18n
After that the language files will be updated (and possibly reformatted, which is ok). You can now edit the language files as usual with the new text.
-
Find the language code and country for the language you want to add. If it is a country specific language variant it should be of the form
xx-XX, where the latter part is the country code. If it is not country specific, the language code is simply of the formxx. Check out the list of language codes on Wikipedia and see Set 1. Also, for country specific languages, check out this site: Country Code Language List. -
With the code, add the language in
angular.json. Add it as a locale insidei18n > locales, and the language code inside the JSONarchitect > build > options > localize{ ... "projects": { "pkspot": { ... "i18n": { ... "locales": { ... "de": { "translation": "src/locale/messages.de.xlf", "baseHref": "/de/" }, // add your new language here // with its language code xx-XX or xx similar to above... // "xx-XX": { // "translation": "src/locale/messages.xx-XX.xlf", // "baseHref": "/xx-XX/" // } } ... }, "architect": { "build": { "builder": "@angular/build:application", "options": { "localize": ["en", "de", "xx-XX"], // add you language here too ... } ... } ... } ... } } } -
Copy an existing language file like
messages.de.xlfinsrc/localeand paste it with the same name as inangular.json, e.g.messages.xx-XX.xlformessages.xx.xlf. -
Edit this new language file in
src/locale. -
Submit a pull-request with your changes on GitHub
PK Spot uses Google Maps. To test the map locally, you need your own Google API key.
- Generate your own Google API key
- Enter it in
keys.development.ts - Build for the development environment when developing locally
Install dependencies:
npm install
Run the development server:
npm run dev
Build the app:
npm run build
Start the SSR server after building:
npm run serve:ssr
Run the main local verification pass:
npm run test:all
Useful narrower checks:
npm run test:unit
npm run test:build
npm run test:e2e
Most maintenance jobs are triggered by creating a Firestore document with the
exact path listed below. Unless a payload is shown, {} is enough.
For production, use the Firebase Console:
- Open Firestore.
- Create the collection/doc path from the table, for example
maintenance/run-backfill-storage-image-sizes. - Add the payload fields if needed.
- Watch the same doc or Cloud Functions logs for completion.
| Job | Firestore document | Payload | Completion |
|---|---|---|---|
Backfill missing image sizes (200, 400, 800) for spot, profile, post, and event images. Reads originals from the public media path and from resized_originals/. |
maintenance/run-backfill-storage-image-sizes |
{} |
Deletes the run doc and writes maintenance/last-storage-image-size-backfill. |
Backfill optional 1600 images too. |
maintenance/run-backfill-storage-image-sizes |
{ "include1600": true } |
Deletes the run doc and writes maintenance/last-storage-image-size-backfill. |
| Backfill only selected image sizes. | maintenance/run-backfill-storage-image-sizes |
{ "sizes": [1600] } |
Deletes the run doc and writes maintenance/last-storage-image-size-backfill. |
Example image backfill payload:
{
"include1600": true
}| Job | Firestore document | Payload | Completion |
|---|---|---|---|
| Recompute spot Typesense helper fields. | maintenance/run-backfill-typesense-fields |
{} |
Deletes the run doc. |
| Recompute spot landing/search helper fields. | maintenance/run-backfill-landing |
{} |
Updates the run doc with status: "DONE". |
| Refresh spot addresses from geocoding. | maintenance/run-update-addresses |
{} |
Deletes the run doc on success; otherwise leaves status: "DONE_WITH_ERRORS". |
| Audit reserved spot slugs. | maintenance/run-audit-reserved-slugs |
{} |
Updates the run doc with status: "DONE" or status: "FAILED". |
| Detect possible duplicate spots within the duplicate radius. | maintenance/run-detect-duplicate-spots |
{} |
Check Cloud Functions logs. |
| Job | Firestore document | Payload | Completion |
|---|---|---|---|
| Recompute event Typesense helper fields. | maintenance/run-backfill-event-typesense-fields |
{} |
Deletes the run doc. |
| Rebuild public event discovery. | maintenance/run-rebuild-event-discovery |
{ "dry_run": false } |
Retains progress and finishes with status: "DONE" or status: "DONE_WITH_ERRORS". |
| Rebuild generated community pages. | maintenance/run-rebuild-community-pages |
{} |
Updates the run doc with status: "DONE" and writes warnings to maintenance/community-warnings when needed. |
| Job | Firestore document | Payload | Completion |
|---|---|---|---|
Convert spot location maps back to Firestore GeoPoints. |
spots/run-fix-locations |
{} |
Deletes the run doc. |
| Normalize old spot locale maps. | spots/run-fix-locale-maps |
{} |
Deletes the run doc. |
| Backfill user signup numbers from Auth creation time. | users/run-backfill-signup-numbers |
{} |
Deletes the run doc. |
| Recalculate user edit statistics from edit documents. | users/run-recalculate-edit-stats |
{} |
Deletes the run doc. |
Material Symbols are self-hosted and subsetted for performance.
- Filled rounded icons come from
src/assets/fonts/icons_list.txtand render through the defaultMaterial Symbols Roundedfont. - Outlined rounded icons come from
src/assets/fonts/icons_outline_list.txtand render through the tinyMaterial Symbols Rounded Outlinedfont. - If an outlined state uses a legacy alias such as
star_border,bookmark_border, ormobile_border, make sure the alias is mapped to the real glyph name inscripts/optimize_icons.py. - Listing an icon in
icons_outline_list.txtonly includes it in the generated outline font. The element must also usematerial-symbols-rounded-outlineorfont-family: "Material Symbols Rounded Outlined"; otherwise<mat-icon>uses the default filled font. - After changing either icon list or alias map, run:
npm run icons:optimize