virtual update from "jama"
This commit is contained in:
48
.env.fcmtest-push
Normal file
48
.env.fcmtest-push
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
#** Required
|
||||||
|
DB_PASSWORD=C@nuck2024
|
||||||
|
JWT_SECRET=changemesupersecretjwtkey
|
||||||
|
|
||||||
|
#** App identity
|
||||||
|
PROJECT_NAME=rosterchirp-dev
|
||||||
|
APP_NAME=RosterChirp
|
||||||
|
DEFCHAT_NAME=General Chat
|
||||||
|
ADMIN_NAME=Admin User
|
||||||
|
ADMIN_EMAIL=admin@rosterchirp.local
|
||||||
|
ADMIN_PASS=Admin@1234
|
||||||
|
ADMPW_RESET=false
|
||||||
|
|
||||||
|
#** Database
|
||||||
|
# DB names intentionally kept as 'rosterchirp' — matches the existing live database
|
||||||
|
DB_NAME=rosterchirp
|
||||||
|
DB_USER=rosterchirp
|
||||||
|
# DB_HOST and DB_PORT are set automatically in docker-compose (host=db, port=5432)
|
||||||
|
|
||||||
|
#** Tenancy mode
|
||||||
|
# selfhost = single tenant (RosterChirp-Chat / RosterChirp-Brand / RosterChirp-Team)
|
||||||
|
# host = multi-tenant (RosterChirp-Host only)
|
||||||
|
APP_TYPE=host
|
||||||
|
|
||||||
|
#** RosterChirp-Host only (ignored in selfhost mode)
|
||||||
|
HOST_DOMAIN=rosterchirp.com
|
||||||
|
HOST_ADMIN_KEY=VBGFHEANTTGRDDWAASJKH
|
||||||
|
|
||||||
|
#** Optional
|
||||||
|
PORT=3244
|
||||||
|
TZ=America/Toronto
|
||||||
|
|
||||||
|
#** Firebase Cloud Messaging (FCM) — Android background push
|
||||||
|
# Web app config — from Firebase Console → Project Settings → General → Your apps
|
||||||
|
FIREBASE_API_KEY=AIzaSyAw1v4COZ68Po8CuwVKrQq0ygf7zFd2QCA
|
||||||
|
FIREBASE_PROJECT_ID=fcmtest-push
|
||||||
|
FIREBASE_MESSAGING_SENDER_ID=439263996034
|
||||||
|
FIREBASE_APP_ID=1:439263996034:web:62a6a6b0afdbad99fdec9b
|
||||||
|
# VAPID key — from Firebase Console → Project Settings → Cloud Messaging → Web Push certificates
|
||||||
|
FIREBASE_VAPID_KEY=BE6hPKkbf-h0lUQ1tYo249pBOdZFFcWQn9suwg3NDwSE8C_hv8hk1dUY9zxHBQEChO_IAqyFZplF_SUb5c4Ofrw
|
||||||
|
# Service account — from Firebase Console → Project Settings → Service accounts → Generate new private key
|
||||||
|
FIREBASE_SERVICE_ACCOUNT={"type": "service_account", "project_id": "fcmtest-push", "private_key_id": "ddbf38d0c5f769b9b8b95000bf05c42b52bb58ad", "private_key": "-----BEGIN PRIVATE KEY-----\nMIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDR4jqMb/0UPVpU\nctpVl9UWHY5lePR4hMEoodbRPofNQgtvx5HuFE61cVrquD8mfUmFB9eZc112KPyy\nMuuZHFkJrVT3iEhK8AoeJTNbxh+YiQvwMhyn9/KO4ntr/HIZxqHs62M46rqehZFS\nFR79zG1ptl/hRFkTTwQoQOOAdqP6gJuX+XpKpVeLPNCBVOAhfM8APA4dvjXUqhrk\ns+L5sH8xdttY/XFdjNhiUtv7uHuvww1hBKliUL6dDZZAlm3uwuYAdsvIHkDWOJ+B\nn8EE7n01h5PUpOihQ2poBAFGHvrT9ifk3bzuGviE74ejErCbBEBwJZvvsaebvaG4\n5dI3SQLXAgMBAAECggEAELX0d24LNmtUH9ktLRdzrdkYl1e0D0xynKuWEP7rjRov\nEu1O3yfaxHOMC5gz3vqmueLP9bXLwTauN/n57Cznoe+dDkBZkS3fgFrx5eK2bUys\nGKnEwlLpixrZPNXSt96q0dRECCoYRbrYwTJRT1/RblNI+wSYGwN1j0brVjUcBTvH\nPjpnt9bkIS+Rb1XJg1+TfQFzt1/WvFscpDpc7zUCGczgD7hAXJU2v2NYZyNtjn2g\niFD4r0AODuFk1Z6C8fbUsgcl8AXXQnJSLPTUXnyzifzBVQmGBu3HewLDHI99pTCZ\nT8aOwgaWYUWrjeg0jfyid08j14OfhE58/PuYGwcNsQKBgQDoh1R/OQ147D75BpXP\nEI1TyKTJNZiwnzRnP64cmzAwbIfc6w06hXTJGKIVqMBwM31R8WUfJ5cBxQOb1g3a\nZDgOTz4zO9M0mFyE/L0V3XrTXzCgPN+pCbZjcAw8oizF3u2rupM5lppxuXnkDiSi\nA2GuVdPR6M8pXUmNubs5XNe1jQKBgQDnEb21yF1K2IF9p1T0jcqLkzDLZDHHudVr\ndZSVVEyhpIFmBFgF8EC3C/ehA5i8Ar1K5JvcP5hpAH345QWOUUAKk000A4WpazZx\nfZM5Ema1xju1AFOSMDzwjt4N32Dg1VPqiLDT+CjiQFH67lSretO1IpS//IKT1Y+W\nOv3/ENfm8wKBgHt7moixUJE9zDdMovPCU3sB21iq6Loq4ZZO//RbCV091WyhOnYw\ndxNvzGt6IS+0eEGy0sOXr56V9FOmedbXT9lxhZOJmqCcpM1Otk9NPbPQIi+GBDRt\nXvkxgJ4WdXZi6449139Glh/8ollUlWmgKBh/pawcWR8bVjs4Pc+5mSflAoGAYfMm\nTRmrWl/evGojXCuC8ZmqdH17kKOY8Z19J7P9bAP1Ck7LFXFbrXx4Mxv4MbKjlUzF\nOR8IN3KK8+f5a/PLRvBcKLFZhpC5GnDV6LqBKYrnonmJ841ZN8wIGy9WvNgRY3kg\nJCqtAgOr/MfswmgluEH5dkzO+WXtIQzOwMHeE7sCgYAhrJV+PvnbnaIpfTaOKXGl\nsvzSXTuey5fQQLKMKsp2haKDVZ2hadDejRHsLJKVGb+KwdJ1s5WmBJ4L80/MnOKZ\n+9Yby9DKviVx0TbvMUGuAuWMl9syo4ICMVpp0cbeSOCM5/ulYjKSeU3sFKo7aWa9\nU8Pskm36I88orq90OBpWOg==\n-----END PRIVATE KEY-----\n","client_email": "firebase-adminsdk-fbsvc@fcmtest-push.iam.gserviceaccount.com", "client_id": "103917424542871804597", "auth_uri": "https://accounts.google.com/o/oauth2/auth", "token_uri": "https://oauth2.googleapis.com/token","auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs", "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/firebase-adminsdk-fbsvc%40fcmtest-push.iam.gserviceaccount.com", "universe_domain": "googleapis.com" }
|
||||||
|
|
||||||
|
RC_VERSION=latest
|
||||||
|
|
||||||
|
VAPID_SUBJECT=mailto:devpush@rosterchirp.com
|
||||||
|
VAPID_PUBLIC=BGYS6vMY7zlx31UKRN9QcaOwfomoDJ50_MtfTcfE84q5bhTLq0rM1zSa6uzBTRBxZuFW1kMQP7ardN_jog3T14Y
|
||||||
|
VAPID_PRIVATE=8SnDSEy_gs2jNwXLtOchZfHW0ppy_RG8wtvjSjYGA48
|
||||||
152
FEATURES.md
Normal file
152
FEATURES.md
Normal file
@@ -0,0 +1,152 @@
|
|||||||
|
# RosterChirp — Feature Reference
|
||||||
|
|
||||||
|
> **Current version:** 0.12.42
|
||||||
|
> **Application types:** RosterChirp-Chat · RosterChirp-Brand · RosterChirp-Team
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## All Users
|
||||||
|
|
||||||
|
### Messaging
|
||||||
|
|
||||||
|
- **Public Messages** — Read and post in public group channels open to all members. Channels can be marked read-only by an admin (announcements-style).
|
||||||
|
- **Private Group Messages** — Participate in named private groups with a specific set of members.
|
||||||
|
- **Direct Messages (U2U)** — Start a private one-on-one conversation with any user who has not blocked direct messages.
|
||||||
|
- **Group Messages** — Access managed private group conversations assigned to you through User Groups (requires RosterChirp-Team).
|
||||||
|
- **Message History** — Scroll back through conversation history with paginated loading (50 messages per page).
|
||||||
|
- **Message Reactions** — React to any message with an emoji.
|
||||||
|
- **Image Sharing** — Attach and send images in any conversation.
|
||||||
|
- **Reply Threading** — Reply to a specific message to preserve context.
|
||||||
|
- **@Mentions** — Mention users by name; mentioned users receive a notification badge.
|
||||||
|
- **Link Previews** — URLs pasted into messages automatically generate a title/image preview card.
|
||||||
|
- **Message Deletion** — Authors can delete their own messages; deleted messages are replaced with a tombstone.
|
||||||
|
|
||||||
|
### Schedule (requires RosterChirp-Team)
|
||||||
|
|
||||||
|
- **Calendar View** — Browse events in a full monthly calendar grid (desktop) or a day-list view (mobile).
|
||||||
|
- **Event Details** — Tap any event to view its full details: date/time, location, description, event type, assigned user groups, and recurrence pattern.
|
||||||
|
- **Availability Response** — Respond to events with **Going**, **Maybe**, or **Not Going**, plus an optional short note (up to 20 characters).
|
||||||
|
- **Bulk Availability** — Respond to multiple pending events at once from a single screen.
|
||||||
|
- **Response Summary** — See how many group members have responded Going / Maybe / Not Going on any event you are assigned to.
|
||||||
|
- **Filter & Search** — Filter the calendar by event type, keyword, or your own availability status. Keyword search supports word-boundary matching and exact quoted terms.
|
||||||
|
|
||||||
|
### Profile & Account
|
||||||
|
|
||||||
|
- **Display Name** — Set a public display name shown alongside your username (must be unique).
|
||||||
|
- **Avatar** — Upload a custom profile photo. A consistent colour avatar is generated automatically from your name if no photo is set.
|
||||||
|
- **About Me** — Add a short bio visible on your profile.
|
||||||
|
- **Hide Admin Tag** — Admins can choose to hide the "Admin" role badge on their messages.
|
||||||
|
- **Block Direct Messages** — Opt out of receiving unsolicited direct messages from other users.
|
||||||
|
- **Change Password** — Change your own account password at any time.
|
||||||
|
- **Font Scale** — Adjust the interface text size (80%–200%) stored per-device.
|
||||||
|
|
||||||
|
### Notifications & Presence
|
||||||
|
|
||||||
|
- **Push Notifications** — Receive push notifications for new messages when the app is backgrounded. Supports Android (Firebase Cloud Messaging) and iOS 16.4+ PWA (Web Push / VAPID).
|
||||||
|
- **Notification Permission** — Grant or revoke push notification permission from the Notifications tab in your profile.
|
||||||
|
- **Unread Badges** — Conversations with unread messages display a count badge in the sidebar and on the PWA app icon.
|
||||||
|
- **Online Presence** — A green indicator shows which users are currently active. Last-seen time is displayed for offline users.
|
||||||
|
- **Browser Tab Badge** — The page title and PWA icon badge update with the total unread count across all conversations.
|
||||||
|
|
||||||
|
### App Experience
|
||||||
|
|
||||||
|
- **Progressive Web App (PWA)** — Install RosterChirp to your home screen on Android, iOS, and desktop for a native app feel.
|
||||||
|
- **Dark / Light Theme** — The interface respects your operating system's colour scheme preference automatically.
|
||||||
|
- **Mobile-Optimised Layout** — A dedicated mobile layout with a slide-in sidebar, swipe-back navigation, and mobile-native time/date pickers.
|
||||||
|
- **Keyboard Shortcuts** — Press Enter to send messages; Escape to dismiss modals.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Managers (Tool Managers)
|
||||||
|
|
||||||
|
Tool Manager access is granted by an admin to members of one or more designated **User Groups**. Managers have access to the following tools in addition to all user features.
|
||||||
|
|
||||||
|
### User Manager
|
||||||
|
|
||||||
|
- **View All Users** — Browse the full user directory including email, role, phone, status, and last seen time.
|
||||||
|
- **Create Users** — Add individual new user accounts with name, email, role, and phone.
|
||||||
|
- **Bulk Import** — Import multiple users at once from a structured list (CSV-compatible).
|
||||||
|
- **Edit Users** — Update names, email addresses, phone numbers, and minor status for any user.
|
||||||
|
- **Suspend / Activate** — Suspend a user to block login without deleting their account or messages. Reversible at any time.
|
||||||
|
- **Reset Password** — Set a new temporary password for any user.
|
||||||
|
|
||||||
|
### Group Manager (requires RosterChirp-Team)
|
||||||
|
|
||||||
|
- **Create User Groups** — Create named user groups to organise members into teams or departments.
|
||||||
|
- **Manage Members** — Add or remove users from any user group. Member changes trigger a system notification in the group's conversation.
|
||||||
|
- **Multi-Groups** — Create a multi-group conversation that spans multiple user groups simultaneously.
|
||||||
|
- **Assign Schedule Groups** — Link user groups to schedule events to control who is invited and whose availability is tracked.
|
||||||
|
|
||||||
|
### Schedule Manager (requires RosterChirp-Team)
|
||||||
|
|
||||||
|
- **Create Events** — Create new calendar events with title, type, date/time, location, description, visibility (public/private), and assigned user groups.
|
||||||
|
- **Edit & Delete Events** — Modify or remove any event. Recurring events support editing/deleting a single occurrence, all future occurrences, or the entire series.
|
||||||
|
- **Recurring Events** — Schedule repeating events (daily, weekly, bi-weekly, monthly) with optional end date or occurrence count. Supports specific weekday selection for weekly recurrence.
|
||||||
|
- **Event Types** — Create and manage colour-coded event type categories (e.g. Training, Match, Meeting).
|
||||||
|
- **Track Availability** — Enable availability tracking on an event to collect Going / Maybe / Not Going responses from assigned group members.
|
||||||
|
- **View Full Responses** — See the complete list of who has responded and with what answer, including individual notes. The **No Response** count shows how many assigned members have not yet replied.
|
||||||
|
- **Download Availability List** — Export a formatted `.txt` file of all availability responses for an event, organised by section (Going, Maybe, Not Going, No Response) and sorted alphabetically by last name within each section.
|
||||||
|
- **Import Schedule** — Upload and preview a schedule import file, then confirm to bulk-create events.
|
||||||
|
- **Past Event Visibility** — View and manage past events in the calendar; past events are displayed in a greyed style.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Admins
|
||||||
|
|
||||||
|
Admins have full access to all user and manager features plus the following administrative controls.
|
||||||
|
|
||||||
|
### User Manager (extended)
|
||||||
|
|
||||||
|
- **Delete Users** — Permanently scrub a user's account: email and name are anonymised, all their messages are marked deleted, and direct message threads become read-only. Frees the email address for re-registration immediately.
|
||||||
|
- **Assign Roles** — Promote or demote users between the **User**, **Manager**, and **Admin** roles.
|
||||||
|
|
||||||
|
### Settings
|
||||||
|
|
||||||
|
- **Message Features** — Enable or disable individual message channel types across the entire instance: Public Messages, Group Messages, Private Group Messages, and Private Messages (U2U). Disabled features are hidden from all menus, sidebars, and modals.
|
||||||
|
- **Registration** — Apply a registration code to unlock the application type (Chat / Brand / Team) and associated features. View the instance serial number and current registration status.
|
||||||
|
|
||||||
|
### Branding (requires RosterChirp-Brand or higher)
|
||||||
|
|
||||||
|
- **App Name** — Set a custom application name that appears in the header, browser tab, and push notifications.
|
||||||
|
- **Logo / Favicon** — Upload a custom logo used as the app header image and PWA icon (192×512 px generated automatically).
|
||||||
|
- **Header Colour** — Set custom header bar colours for light mode and dark mode independently.
|
||||||
|
- **Avatar Colours** — Customise the default avatar colours used for public channel icons and direct message icons.
|
||||||
|
- **Reset Branding** — Restore all branding settings to the default RosterChirp values in one click.
|
||||||
|
|
||||||
|
### Team Configuration (requires RosterChirp-Team)
|
||||||
|
|
||||||
|
- **Tool Manager Groups** — Designate one or more User Groups whose members are granted Tool Manager access (User Manager, Group Manager, Schedule Manager). Admins always have full access regardless of this setting.
|
||||||
|
|
||||||
|
### Control Panel (Host mode only — admin on the host domain)
|
||||||
|
|
||||||
|
- **Tenant Management** — View, create, suspend, and delete tenant instances from a central dashboard.
|
||||||
|
- **Assign Plans** — Set the application type (Chat / Brand / Team) for each tenant.
|
||||||
|
- **Custom Domains** — Assign a custom domain to a tenant in addition to its default subdomain.
|
||||||
|
- **Tenant Details** — View each tenant's slug, plan, status, custom domain, and creation date.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Hosting & Tenant Privacy
|
||||||
|
|
||||||
|
RosterChirp supports two deployment modes configured via the `APP_TYPE` environment variable.
|
||||||
|
|
||||||
|
### Self-Hosted (Single Tenant)
|
||||||
|
|
||||||
|
`APP_TYPE=selfhost` — The default mode for teams running their own private instance. All data is stored in a single PostgreSQL schema. There are no subdomains or tenant concepts; the application runs at the root of whatever domain or IP the server is deployed on.
|
||||||
|
|
||||||
|
### RosterChirp-Host (Multi-Tenant)
|
||||||
|
|
||||||
|
`APP_TYPE=host` — Enables multi-tenant hosting from a single server. Each tenant is provisioned with:
|
||||||
|
|
||||||
|
- **A unique slug** — for example, the slug `acme` creates a dedicated instance accessible at `acme.yourdomain.com`. The slug is set at provisioning time and forms the permanent subdomain for that tenant.
|
||||||
|
- **An isolated Postgres schema** — every tenant's data (users, messages, groups, events, settings) lives in its own named schema (`tenant_acme`, etc.) within the same database. No data is shared between tenants.
|
||||||
|
- **An optional custom domain** — a tenant can be mapped to a fully custom domain (e.g. `chat.acme.com`) in addition to its default subdomain. Custom domain lookups are cached for performance.
|
||||||
|
- **Plan-level feature control** — each tenant can be assigned a different application type (Chat / Brand / Team), enabling per-tenant feature gating from the host control panel.
|
||||||
|
|
||||||
|
### Privacy & Isolation Guarantees
|
||||||
|
|
||||||
|
- **Schema isolation** — all database queries are scoped to the tenant's schema. A query in one tenant's context cannot read or write another tenant's tables.
|
||||||
|
- **Socket room isolation** — all real-time socket rooms are prefixed with the tenant schema name (`acme:group:42`). Events emitted in one tenant's rooms cannot reach sockets in another tenant.
|
||||||
|
- **Online presence isolation** — the online user map is keyed by `schema:userId`, preventing user ID collisions between tenants from leaking presence data.
|
||||||
|
- **Session isolation** — JWT tokens are validated against the tenant schema. A valid token for one tenant is not accepted by another.
|
||||||
|
- **Host control plane separation** — the host admin control panel is only accessible on the host's own root domain, protected by a separate `HOST_ADMIN_KEY`, and hidden from all tenant subdomains.
|
||||||
63
Reference/minor-age-protection.txt
Normal file
63
Reference/minor-age-protection.txt
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
RULE: minor age is when DOB is 15 years and under.
|
||||||
|
|
||||||
|
User manager:
|
||||||
|
Enable "Date of Birth" field (default optional unless "Mixed Age" is selected in the (new) as "Login Type" on Settings modal page)
|
||||||
|
Enable "Guardian" field as optional
|
||||||
|
|
||||||
|
My Profile modal:
|
||||||
|
Change: replace tab buttons with a select list labled "SELECT OPTION:" Profile - default selected (on both desktop and mobile)
|
||||||
|
On the "Profile" tab, add two new text inputs: Date of Birth and Phone (same format field verification as used in the user manager field) - once saved, user manager is updated with data from these two fields for the given user
|
||||||
|
Add a new select option "Add Child" (only displayed IF the new "Login Type" setting has either "Guardians Only" or "Mixed Age" selected.
|
||||||
|
|
||||||
|
"Add Child" Form:
|
||||||
|
- (on user's my profile): Firstname, Lastname, Email, DOB, Profile avatar (follow avatar upload rules), number (input box), Add button, Save button (disabled until there is a child added to guardian's child list)
|
||||||
|
- Clicking the Add button will add child to the guardians child list.)
|
||||||
|
- Clicking save, will save the the guardian's child list and will each child entry to players user group.
|
||||||
|
|
||||||
|
Settings modal:
|
||||||
|
Change: replace tab tabs buttons to a select list, labelled "SELECT OPTION" Messages is still the default option (on both desktop and mobile)
|
||||||
|
Add new selection "Login Type" to the list, form details below:
|
||||||
|
|
||||||
|
An option list with brief description under:
|
||||||
|
Option: "Guardian Only"
|
||||||
|
Descriptions: "Parents are required to add their child's details in their profile. They will respond on behalf of the child for events with availability tracking for the "players" group".
|
||||||
|
|
||||||
|
- User manager DOB is optional
|
||||||
|
- "Players" user group entry will be the child's name as an alias to the guardians account, if more than one child each entry will be treated uniquely for mentions and event availabillty responses.
|
||||||
|
- "Players" User Group DM will be disabled/hidden and cannot be added to Multi-Group DMs
|
||||||
|
- The event modal with Availabilty requested for the "players" user group, will have a new drop down select list (under the response buttons, above the note input box - hidden/disabled by default) and will only be unhidden/enable if the event includes the "players" user group, and only displayed for user who have a saved child list of at least one. The select list options will include the guardians child list, AND will also the guardian's name IF multiple user groups are selected for the event, with one be players, and at least one being a user group that the guardian is a member of that is not the players group. There will be a default option of "ALL", if selected, the response and note (if entered) will be the same for all "people" listed in the select list, but responses will be listed indivually in the response list for the event.
|
||||||
|
|
||||||
|
Scenario 1: Event: party, track availability enabled, groups selected: players + parents
|
||||||
|
- select drop down will display option: "All" default selected, then guadians name on row 2 (parent user group), each child's name on susequent rows (listed in the players user group owned by the guardian)
|
||||||
|
- selecting "All" will add each "person" in the select drop down list individually to the reponse list, but with the same availability and note (if entered) for each
|
||||||
|
- selecting an idividual name will add response for that indivual only (so they can each have different responses and notes) - repeats per indivual in the select list
|
||||||
|
Scenario 2: Event, track availability enabled, groups selected: players
|
||||||
|
- select drop down will display "All" on the top row, each child's name (listed in the players user group and owned by the guardian)
|
||||||
|
- selecting "All" will add each "person" in the select drop down list individually to the reponse list, but with the same availability and note (if entered) for each
|
||||||
|
- selecting an idividual name in the selectlist will add response for that indivual only (so they can each have different responses and notes) - repeats per indivual in the select list
|
||||||
|
Scenario 3: Event, track availability enabled, groups selected: parents
|
||||||
|
- select drop down is hidden
|
||||||
|
- availability response and note is for the guardian only
|
||||||
|
|
||||||
|
Option: "Mixed Age"
|
||||||
|
Descriptions: "Parents, or user managers, are required to add the minor aged child's user account to the guardians user profile. Minor aged users cannot login until this is complete."
|
||||||
|
- User manager DOB is required for all users
|
||||||
|
- Minor aged user's account are automatically suspended
|
||||||
|
on the add child form:
|
||||||
|
- search user input field, will display only a list of minor aged users. Selecting a user fills out the "Add Child" read-only form
|
||||||
|
- "Add Child" Form all fields are read-only: Firstname, Lastname, DOB*, user's avatar, number (input box), Add button when form is filled by selecting a user, Save button (disabled until there is a child added to guardian's child list). Requires admin approval. A message is sent to all users with the managers from from the default admin user account indicating "User Manager requires approval".
|
||||||
|
- The minor user account name that requires gaurdina name approval is bold red in the user manager list. When the "editing" user account, the Gaurdian field will be highlighted in red. Besides the label will be two link options [approve - green] [deny - red] (same size font as the label). Approve will clear the approval required flag and unsuspend the user account, with the guardian name save to the user's profile.
|
||||||
|
- Saving the form will update the minor aged user account with a guardian name, requires a user with manager role approval, once approved, the minor's user account is unsuspended.
|
||||||
|
- Events are handled like they are currently
|
||||||
|
- Guardians are not part of players user group DMs
|
||||||
|
- Guardians do not respond to availability on the childs behalf (new select list on the event form remains hidden/diabled)
|
||||||
|
- any private messages initiated by a user 18 years or older to a minor aged will automatically include the guardian user account as well.
|
||||||
|
-> a modal confirmation will be provide to the 18+ user that they are messaging a user that will also include their parent/guardian.
|
||||||
|
|
||||||
|
Option: All Ages (default selection)
|
||||||
|
- "Add Child" hidden/disbled Profile select option list.
|
||||||
|
- Aliase select list is hidden/disabled
|
||||||
|
- Events are handled like they are currently
|
||||||
|
|
||||||
|
Yellow warning symbol and text below: "This setting can only be set/changed when the user table in the database is empty." (form is read-only unless user manager is empty OR only has users with the admin role).
|
||||||
|
- if the setting is changed and users exisit with admin role, on each subsequent login the user's profile modal popup until the Date of Birth is entered.
|
||||||
66
docker-compose-fcmtest-push.yaml
Normal file
66
docker-compose-fcmtest-push.yaml
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
services:
|
||||||
|
rosterchirp:
|
||||||
|
image: rosterchirp-dev:${RC_VERSION:-latest}
|
||||||
|
container_name: ${PROJECT_NAME:-rosterchirp}
|
||||||
|
restart: unless-stopped
|
||||||
|
ports:
|
||||||
|
- "${PORT:-3000}:3000"
|
||||||
|
environment:
|
||||||
|
- NODE_ENV=production
|
||||||
|
- TZ=${TZ:-UTC}
|
||||||
|
- APP_TYPE=${APP_TYPE:-selfhost}
|
||||||
|
- ADMIN_NAME=${ADMIN_NAME:-Admin User}
|
||||||
|
- ADMIN_EMAIL=${ADMIN_EMAIL:-admin@rosterchirp.local}
|
||||||
|
- ADMIN_PASS=${ADMIN_PASS:-Admin@1234}
|
||||||
|
- ADMPW_RESET=${ADMPW_RESET:-false}
|
||||||
|
- JWT_SECRET=${JWT_SECRET:-changeme_super_secret_jwt_key_2024}
|
||||||
|
- APP_NAME=${APP_NAME:-rosterchirp}
|
||||||
|
- DEFCHAT_NAME=${DEFCHAT_NAME:-General Chat}
|
||||||
|
- DB_HOST=db
|
||||||
|
- DB_PORT=5432
|
||||||
|
- DB_NAME=${DB_NAME:-rosterchirp}
|
||||||
|
- DB_USER=${DB_USER:-rosterchirp}
|
||||||
|
- DB_PASSWORD=${DB_PASSWORD:?DB_PASSWORD is required}
|
||||||
|
- HOST_DOMAIN=${HOST_DOMAIN:-}
|
||||||
|
- HOST_ADMIN_KEY=${HOST_ADMIN_KEY:-}
|
||||||
|
- FIREBASE_API_KEY=${FIREBASE_API_KEY:-}
|
||||||
|
- FIREBASE_PROJECT_ID=${FIREBASE_PROJECT_ID:-}
|
||||||
|
- FIREBASE_MESSAGING_SENDER_ID=${FIREBASE_MESSAGING_SENDER_ID:-}
|
||||||
|
- FIREBASE_APP_ID=${FIREBASE_APP_ID:-}
|
||||||
|
- FIREBASE_VAPID_KEY=${FIREBASE_VAPID_KEY:-}
|
||||||
|
- FIREBASE_SERVICE_ACCOUNT=${FIREBASE_SERVICE_ACCOUNT}
|
||||||
|
- VAPID_SUBJECT=${VAPID_SUBJECT:-mailto:push@rosterchirp.com}
|
||||||
|
- VAPID_PUBLIC=${VAPID_PUBLIC:-CHANGEME}
|
||||||
|
- VAPID_PRIVATE=${VAPID_PRIVATE:-CHANGEME}
|
||||||
|
volumes:
|
||||||
|
- rosterchirp_uploads:/app/uploads
|
||||||
|
depends_on:
|
||||||
|
db:
|
||||||
|
condition: service_healthy
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "wget", "-q", "--spider", "http://localhost:3000/api/health"]
|
||||||
|
interval: 30s
|
||||||
|
timeout: 10s
|
||||||
|
retries: 3
|
||||||
|
|
||||||
|
db:
|
||||||
|
image: postgres:16-alpine
|
||||||
|
container_name: ${PROJECT_NAME:-rosterchirp}_db
|
||||||
|
restart: unless-stopped
|
||||||
|
environment:
|
||||||
|
- POSTGRES_DB=${DB_NAME:-rosterchirp}
|
||||||
|
- POSTGRES_USER=${DB_USER:-rosterchirp}
|
||||||
|
- POSTGRES_PASSWORD=${DB_PASSWORD:?DB_PASSWORD is required}
|
||||||
|
volumes:
|
||||||
|
- rosterchirp_db:/var/lib/postgresql/data
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD-SHELL", "pg_isready -U ${DB_USER:-rosterchirp} -d ${DB_NAME:-rosterchirp}"]
|
||||||
|
interval: 5s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 10
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
rosterchirp_db:
|
||||||
|
driver: local
|
||||||
|
rosterchirp_uploads:
|
||||||
|
driver: local
|
||||||
13
fcmtest-push-firebase-adminsdk-fbsvc-ddbf38d0c5.json
Normal file
13
fcmtest-push-firebase-adminsdk-fbsvc-ddbf38d0c5.json
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
{
|
||||||
|
"type": "service_account",
|
||||||
|
"project_id": "fcmtest-push",
|
||||||
|
"private_key_id": "ddbf38d0c5f769b9b8b95000bf05c42b52bb58ad",
|
||||||
|
"private_key": "-----BEGIN PRIVATE KEY-----\nMIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDR4jqMb/0UPVpU\nctpVl9UWHY5lePR4hMEoodbRPofNQgtvx5HuFE61cVrquD8mfUmFB9eZc112KPyy\nMuuZHFkJrVT3iEhK8AoeJTNbxh+YiQvwMhyn9/KO4ntr/HIZxqHs62M46rqehZFS\nFR79zG1ptl/hRFkTTwQoQOOAdqP6gJuX+XpKpVeLPNCBVOAhfM8APA4dvjXUqhrk\ns+L5sH8xdttY/XFdjNhiUtv7uHuvww1hBKliUL6dDZZAlm3uwuYAdsvIHkDWOJ+B\nn8EE7n01h5PUpOihQ2poBAFGHvrT9ifk3bzuGviE74ejErCbBEBwJZvvsaebvaG4\n5dI3SQLXAgMBAAECggEAELX0d24LNmtUH9ktLRdzrdkYl1e0D0xynKuWEP7rjRov\nEu1O3yfaxHOMC5gz3vqmueLP9bXLwTauN/n57Cznoe+dDkBZkS3fgFrx5eK2bUys\nGKnEwlLpixrZPNXSt96q0dRECCoYRbrYwTJRT1/RblNI+wSYGwN1j0brVjUcBTvH\nPjpnt9bkIS+Rb1XJg1+TfQFzt1/WvFscpDpc7zUCGczgD7hAXJU2v2NYZyNtjn2g\niFD4r0AODuFk1Z6C8fbUsgcl8AXXQnJSLPTUXnyzifzBVQmGBu3HewLDHI99pTCZ\nT8aOwgaWYUWrjeg0jfyid08j14OfhE58/PuYGwcNsQKBgQDoh1R/OQ147D75BpXP\nEI1TyKTJNZiwnzRnP64cmzAwbIfc6w06hXTJGKIVqMBwM31R8WUfJ5cBxQOb1g3a\nZDgOTz4zO9M0mFyE/L0V3XrTXzCgPN+pCbZjcAw8oizF3u2rupM5lppxuXnkDiSi\nA2GuVdPR6M8pXUmNubs5XNe1jQKBgQDnEb21yF1K2IF9p1T0jcqLkzDLZDHHudVr\ndZSVVEyhpIFmBFgF8EC3C/ehA5i8Ar1K5JvcP5hpAH345QWOUUAKk000A4WpazZx\nfZM5Ema1xju1AFOSMDzwjt4N32Dg1VPqiLDT+CjiQFH67lSretO1IpS//IKT1Y+W\nOv3/ENfm8wKBgHt7moixUJE9zDdMovPCU3sB21iq6Loq4ZZO//RbCV091WyhOnYw\ndxNvzGt6IS+0eEGy0sOXr56V9FOmedbXT9lxhZOJmqCcpM1Otk9NPbPQIi+GBDRt\nXvkxgJ4WdXZi6449139Glh/8ollUlWmgKBh/pawcWR8bVjs4Pc+5mSflAoGAYfMm\nTRmrWl/evGojXCuC8ZmqdH17kKOY8Z19J7P9bAP1Ck7LFXFbrXx4Mxv4MbKjlUzF\nOR8IN3KK8+f5a/PLRvBcKLFZhpC5GnDV6LqBKYrnonmJ841ZN8wIGy9WvNgRY3kg\nJCqtAgOr/MfswmgluEH5dkzO+WXtIQzOwMHeE7sCgYAhrJV+PvnbnaIpfTaOKXGl\nsvzSXTuey5fQQLKMKsp2haKDVZ2hadDejRHsLJKVGb+KwdJ1s5WmBJ4L80/MnOKZ\n+9Yby9DKviVx0TbvMUGuAuWMl9syo4ICMVpp0cbeSOCM5/ulYjKSeU3sFKo7aWa9\nU8Pskm36I88orq90OBpWOg==\n-----END PRIVATE KEY-----\n",
|
||||||
|
"client_email": "firebase-adminsdk-fbsvc@fcmtest-push.iam.gserviceaccount.com",
|
||||||
|
"client_id": "103917424542871804597",
|
||||||
|
"auth_uri": "https://accounts.google.com/o/oauth2/auth",
|
||||||
|
"token_uri": "https://oauth2.googleapis.com/token",
|
||||||
|
"auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
|
||||||
|
"client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/firebase-adminsdk-fbsvc%40fcmtest-push.iam.gserviceaccount.com",
|
||||||
|
"universe_domain": "googleapis.com"
|
||||||
|
}
|
||||||
206
summary.md
Normal file
206
summary.md
Normal file
@@ -0,0 +1,206 @@
|
|||||||
|
# Mobile UI Fixes Summary
|
||||||
|
**Date:** March 29, 2026
|
||||||
|
**Version:** 0.12.45
|
||||||
|
**Focus:** Android Chrome mobile browser issues
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🎯 **Objective**
|
||||||
|
Fix mobile UI issues in RosterChirp application on Android Chrome browser:
|
||||||
|
1. Chrome autocomplete bar covering input fields
|
||||||
|
2. Calendar popup appearing when selecting end time
|
||||||
|
3. Time dropdowns being hidden by keyboard
|
||||||
|
4. Inconsistent date/time row behavior
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📁 **Files Modified**
|
||||||
|
|
||||||
|
### **Frontend Components**
|
||||||
|
|
||||||
|
#### **1. `frontend/src/components/SchedulePage.jsx`**
|
||||||
|
**Changes Made:**
|
||||||
|
- **TimeInput component:** Added `inputMode="text"` and `enterKeyHint="done"` to prevent calendar popup
|
||||||
|
- **Form wrapper:** Changed from `autoComplete="new-password"` to `autoComplete="off"` for standard behavior
|
||||||
|
- **Dropdown positioning:** Increased z-index from 300 to 9999 to prevent calendar interference
|
||||||
|
- **Input attributes:** Added explicit `type="text"` and `inputMode="text"` for strong calendar prevention
|
||||||
|
|
||||||
|
**Lines Modified:** 187-222
|
||||||
|
|
||||||
|
#### **2. `frontend/src/components/MobileEventForm.jsx`**
|
||||||
|
**Changes Made:**
|
||||||
|
- **TimeInputMobile component:** Complete rewrite with intelligent positioning
|
||||||
|
- **Visual Viewport API:** Added keyboard detection and dynamic positioning
|
||||||
|
- **Smart dropdown logic:** Calculates available space above/below input
|
||||||
|
- **Input attributes:** Added `inputMode="text"` and `enterKeyHint="done"`
|
||||||
|
- **Z-index fix:** Increased to 9999 to prevent calendar interference
|
||||||
|
- **End date/time row structure:** Fixed to match start date/time row
|
||||||
|
|
||||||
|
**Lines Modified:** 72-181, 554-568
|
||||||
|
|
||||||
|
#### **3. `frontend/src/components/UserManagerModal.jsx`**
|
||||||
|
**Changes Made:**
|
||||||
|
- **Form wrapper:** Added `autoComplete="off"` to suppress Chrome autocomplete
|
||||||
|
- **Input consistency:** Ensured all inputs use standard autocomplete suppression
|
||||||
|
|
||||||
|
**Lines Modified:** 293-295
|
||||||
|
|
||||||
|
#### **4. `frontend/src/pages/GroupManagerPage.jsx`**
|
||||||
|
**Changes Made:**
|
||||||
|
- **Form wrapper:** Added `autoComplete="off"` for consistent behavior
|
||||||
|
- **Input attributes:** Standardized autocomplete suppression
|
||||||
|
|
||||||
|
**Lines Modified:** 744-746
|
||||||
|
|
||||||
|
#### **5. `frontend/src/pages/UserManagerPage.jsx`**
|
||||||
|
**Changes Made:**
|
||||||
|
- **Form wrapper:** Added `autoComplete="off"` for mobile compatibility
|
||||||
|
- **Input consistency:** Updated all input fields
|
||||||
|
|
||||||
|
**Lines Modified:** 624-626
|
||||||
|
|
||||||
|
#### **6. `frontend/src/index.css`**
|
||||||
|
**Changes Made:**
|
||||||
|
- **Cleaned up aggressive CSS:** Removed `-webkit-autofill` overrides that could affect iOS/desktop
|
||||||
|
- **Reverted to standard:** Cross-browser compatible approach
|
||||||
|
|
||||||
|
**Lines Modified:** 35-62 (removed aggressive autocomplete CSS)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔧 **Technical Solutions Implemented**
|
||||||
|
|
||||||
|
### **1. Chrome Autocomplete Suppression**
|
||||||
|
```jsx
|
||||||
|
// Standard approach (safe for all browsers)
|
||||||
|
<input autoComplete="off" />
|
||||||
|
<form autoComplete="off">
|
||||||
|
```
|
||||||
|
|
||||||
|
### **2. Calendar Popup Prevention**
|
||||||
|
```jsx
|
||||||
|
// Strong signals to prevent date picker
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
inputMode="text"
|
||||||
|
enterKeyHint="done"
|
||||||
|
autoComplete="off"
|
||||||
|
/>
|
||||||
|
```
|
||||||
|
|
||||||
|
### **3. Smart Dropdown Positioning**
|
||||||
|
```js
|
||||||
|
// Visual Viewport API for keyboard detection
|
||||||
|
const handleViewportChange = () => {
|
||||||
|
if (window.visualViewport) {
|
||||||
|
const offset = window.innerHeight - window.visualViewport.height;
|
||||||
|
setKeyboardOffset(offset > 0 ? offset : 0);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Intelligent positioning based on available space
|
||||||
|
const spaceAbove = rect.top;
|
||||||
|
const spaceBelow = window.innerHeight - rect.bottom - keyboardOffset;
|
||||||
|
|
||||||
|
if (spaceBelow >= dropdownHeight) {
|
||||||
|
setDropdownPosition({ top: '100%', bottom: 'auto' });
|
||||||
|
} else {
|
||||||
|
setDropdownPosition({ top: 'auto', bottom: '100%' });
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### **4. Z-Index Hierarchy Fix**
|
||||||
|
```jsx
|
||||||
|
// Time dropdowns above all other UI elements
|
||||||
|
zIndex: 9999
|
||||||
|
```
|
||||||
|
|
||||||
|
### **5. Consistent Date/Time Row Structure**
|
||||||
|
```jsx
|
||||||
|
// Before (problematic)
|
||||||
|
<div onClick={()=>setShowEndDate(true)} style={{cursor:'pointer'}}>
|
||||||
|
<span>{date}</span>
|
||||||
|
<TimeInputMobile />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
// After (fixed)
|
||||||
|
<div>
|
||||||
|
<span onClick={()=>setShowEndDate(true)} style={{cursor:'pointer'}}>{date}</span>
|
||||||
|
<TimeInputMobile />
|
||||||
|
</div>
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🐛 **Issues Resolved**
|
||||||
|
|
||||||
|
### **✅ Chrome Autocomplete Bar**
|
||||||
|
- **Status:** Intended Chrome behavior (not a bug)
|
||||||
|
- **Solution:** Standard `autoComplete="off"` implementation
|
||||||
|
- **Result:** Consistent with Google Calendar's own behavior
|
||||||
|
|
||||||
|
### **✅ Calendar Popup on End Time**
|
||||||
|
- **Root Cause:** Z-index conflict and row structure issues
|
||||||
|
- **Solution:** Increased z-index + separate clickable areas
|
||||||
|
- **Result:** Calendar only triggers on date click, not time click
|
||||||
|
|
||||||
|
### **✅ Keyboard Covering Dropdowns**
|
||||||
|
- **Root Cause:** Fixed positioning without keyboard awareness
|
||||||
|
- **Solution:** Visual Viewport API + intelligent positioning
|
||||||
|
- **Result:** Dropdowns appear above keyboard or reposition automatically
|
||||||
|
|
||||||
|
### **✅ Inconsistent Date/Time Rows**
|
||||||
|
- **Root Cause:** Different HTML structure between start/end rows
|
||||||
|
- **Solution:** Made both rows structurally identical
|
||||||
|
- **Result:** Consistent behavior for both date and time interactions
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📱 **Cross-Browser Compatibility**
|
||||||
|
|
||||||
|
### **✅ iOS Safari**
|
||||||
|
- Respects standard `autoComplete="off"`
|
||||||
|
- No aggressive CSS overrides affecting behavior
|
||||||
|
- Smart positioning works with Visual Viewport API
|
||||||
|
|
||||||
|
### **✅ Desktop Browsers**
|
||||||
|
- Standard autocomplete behavior
|
||||||
|
- No interference from mobile-specific fixes
|
||||||
|
- Consistent time dropdown functionality
|
||||||
|
|
||||||
|
### **✅ Android Chrome**
|
||||||
|
- Standard autocomplete suppression (as intended by Chrome)
|
||||||
|
- Proper time dropdown positioning
|
||||||
|
- No calendar interference with time selection
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🎯 **Key Learnings**
|
||||||
|
|
||||||
|
1. **Chrome Android autocomplete is intended behavior**, not a bug
|
||||||
|
2. **Even Google Calendar can't suppress it** - confirmed by user testing
|
||||||
|
3. **Standard HTML attributes are the safest approach** for cross-browser compatibility
|
||||||
|
4. **Visual Viewport API provides reliable keyboard detection**
|
||||||
|
5. **Z-index hierarchy is critical** for preventing UI element conflicts
|
||||||
|
6. **Consistent HTML structure prevents interaction conflicts**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📦 **Version History**
|
||||||
|
- **0.12.38:** Initial autocomplete attempts
|
||||||
|
- **0.12.39:** Aggressive CSS and JavaScript overrides
|
||||||
|
- **0.12.40:** Cleaned up to standard approach
|
||||||
|
- **0.12.41:** Fixed calendar z-index issues
|
||||||
|
- **0.12.42:** Added smart dropdown positioning
|
||||||
|
- **0.12.43:** Fixed date/time row structure
|
||||||
|
- **0.12.44:** Refined positioning logic
|
||||||
|
- **0.12.45:** Final stable implementation
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🚀 **Ready for Deployment**
|
||||||
|
All changes are cross-browser compatible and follow web standards. The implementation now:
|
||||||
|
- Works consistently across iOS Safari, Android Chrome, and desktop browsers
|
||||||
|
- Provides intelligent dropdown positioning
|
||||||
|
- Maintains clean, maintainable code
|
||||||
|
- Follows React best practices
|
||||||
Reference in New Issue
Block a user