Zum Hauptinhalt springen
  1. Work in Progress/

Soccer App - Users Only Attempt

·783 Wörter·4 min
Autor
Kees Fluitman
I am a pedagog, hobbyist, allrounder and self-taught beginning software engineer. I am also a privacy advocate and enjoy privacy enhancing technologies.
Inhaltsverzeichnis
In This Post, I will attempt to dissassemble my database structure. I will remove the players collection. The users will be the only collection for users of any kind. So users can be players, manage other players, manage teams, or manage clubs. This will make complicated cases easier to handle. For instance, where a user is a trainer, parent and player himself.

Schema Changes
#


erDiagram
    USERS {
        string id PK
        string email
        string username
        string name
        boolean disabled
        relation club FK
        relation guardians FK "Users this user is managed by"
        date created
        date updated
    }
    
    CLUBS {
        string id PK
        string name
        string location
		relation managers FK "Users who manage this club"
    }
    
    TEAMS {
        string id PK
        string name
        string category
        relation trainers FK "Users who trains this team"
        relation players FK "Users who play in this team"
        relation club FK
    }
    
    USERS ||--o{ USERS : "manages as guardian"
    USERS ||--o| CLUBS : "is managed by"
    TEAMS ||--o| CLUBS : "belongs to"
    TEAMS ||--o| USERS : "trained by"
    TEAMS ||--o{ USERS : "has players"
erDiagram
    events {
        date date
        string organizer
        string location
    }
    teams {
        string category
        string team
    }
    players {
        string first_name
        string last_name
        date birthday
    }
    clubs {
       string name
       string location
       date founded
   }
    events ||--o{ teams : "participates"
    events ||--o{ players : "participates"
    events ||--o{ clubs : "participates"

Steps
#

What do I have to change in my app?

  1. Git Branch to Users-Only
  2. Initial Serverside load. server.layout.ts
  3. Rewrite Mocking Data Scripts

Data retrieval
#

My Sveltekit app will be partly serverside, partly clientside. This is tough and hard to grasp.

The creator of Pocketbase writes about it himself: JS SSR Issues

When interacting with an external services like PocketBase from a meta JavaScript framework you usually have 3 options:

  1. only from client-side (ex. browser->PocketBase)
  2. only from server-side (ex. browser->node->PocketBase)
  3. mixed - from both client-side and server-side

Pocketbase was designed to be a backend, so using sveltekit as a backend as well, is quite superfluous. But as I’ve got a solid Template working already. Im going with the flow. It will be a challenge. But I’ll try option 3.

Privacy and Data retrieval
#

The data in the users table is accessable to anyone that can View or List the data. But I want to restrict that data to users to see only limited data like the name or age, not email, Social Security Numbers etc. So I’d need a View Collection to accomodate this, which I will use in all other requests, like the calendar.

Below, you can see how I can define only the name and id of the players. So the calendar page doesnt load sensitive information.

eventStore = await watch<ExpandedEvent>(
    'events',
    {
        sort: 'date',
        fields: '*,expand.event_participants_via_event.*,expand.event_participants_via_event.expand.players.id,expand.event_participants_via_event.expand.players.name',
        expand: 'event_participants_via_event.players,teams,clubs',
        filter: filter
    },
    1,
    5
);
The watch function is the function that subscribes to this data, so any changes on the server are updated directly in the client browser.

My plan
#

  • Create View Collections for Users, Teams and Clubs with less fields available.

  • Initial Data Load holds User Data only, with Teams and Clubs that are of interest to the authenticated user. It will contain as little expansion as possible for a better overview and little risk of leaking sensitive data.

  • An event Watcher (the watch function) is initialized clientside only, subscribing to Changes in the pocketbase Backend for Events only.

I will need to pay attention to: Securing all routes that are clientside only, so they cannot be accessed by accident. Securing the API Rules of Pocketbase and using View Collections for less strict View and List access. Not accidently leaking private information.

Rough Structure
#

flowchart TD
    A["Layout Server Load\n(layout.server.ts)"] --> B["Load User"] 
    A --> C["Load Subscription"]
    A --> D["Load User Relations"]
    A --> E["Load Notifications"]
    
    B --> F["PocketBase User Record"]
    C --> G["Stripe Subscription"]
    D --> H1["players[]"]
    D --> H2["teams[]"]
    D --> H3["clubs[]"]
    E --> I["globalNotifications[]"]
    
    F & G & H1 & H2 & H3 & I --> J["Return Flat Data Structure"]
    
    J --> K["Page Data {user, players[], teams[], clubs[], globalNotifications[]}"]
    
    style A fill:#f9d77e,stroke:#f9a11b,stroke-width:2px
    style B fill:#a8d5ba,stroke:#1b8a43
    style C fill:#a8d5ba,stroke:#1b8a43
    style D fill:#a8d5ba,stroke:#1b8a43
    style E fill:#a8d5ba,stroke:#1b8a43
    style J fill:#aac4f5,stroke:#1b54b8
    style K fill:#f5aaa2,stroke:#b81b1b,stroke-width:2px
flowchart TD
    A["Page Data from Server"] --> B["Component Initialization"]
    
    B --> C["Initial State Setup"]
    
    C --> D["currentPlayer (First player or selection)"]
    D -- "Reactive derivation" --> E["currentTeam (Based on player.team ID)"]
    E -- "Reactive derivation" --> F["currentClub (Based on team.club ID)"]
    
    G["User selects different player"] --> D
    
    D --> H["UI Updates (Player profile, team info, club details)"]
    E --> H
    F --> H
    
    style A fill:#f5aaa2,stroke:#b81b1b,stroke-width:2px
    style B fill:#a8d5ba,stroke:#1b8a43
    style C fill:#a8d5ba,stroke:#1b8a43
    style D fill:#aac4f5,stroke:#1b54b8,stroke-width:2px
    style E fill:#aac4f5,stroke:#1b54b8,stroke-width:2px
    style F fill:#aac4f5,stroke:#1b54b8,stroke-width:2px
    style G fill:#f9d77e,stroke:#f9a11b
    style H fill:#d5a8bf,stroke:#8a1b69