Version: 2.6.0 (Updated: 2025-06-10)
Project: A Google Apps Script web application for managing QuakeWorld team schedules.
Architecture: A deliberate, constraint-driven monolith optimized for the Google Apps Script platform.
- LogoService.js → ImageService.js: Renamed and expanded to handle all image operations, not just team logos
- Added generic Drive image support: New
imageService_getDriveImageAsBase64()function for any Google Drive hosted images - Enhanced logo management: Team logos and other images now use base64 proxy to bypass CORS issues
- Discord help image: Now embedded as base64 in Configuration.js for instant loading
A high-level trace of what happens when a user clicks "Join Team" in the UI.
- UI Event (
frontend/02c-team-ui.html): ThehandleJoinTeamSubmitfunction is triggered. - API Call (
frontend/02c-team-ui.html): It callsgoogle.script.run.joinTeamWithCode(joinCode, initials). - Controller (
WebAppController.js): ThejoinTeamWithCodefunction receives the call.- It retrieves the current user's email.
- It calls the core logic in
PlayerDataManager.js.
- Business Logic (
PlayerDataManager.js): ThejoinTeamByCodefunction executes:- Validates the join code using
TeamDataManager.js. - Checks if the player exists; if not, calls
createPlayer(). - Finds an empty team slot for the player.
- Updates the
Playerssheet with the new team ID and role. - Calls
syncTeamPlayerData()to update the denormalized data on theTeamssheet. - Calls
_pdm_updateCurrentWeekRosterBlockOnTeamSheet()to update the roster block on the team's specific schedule sheet.
- Validates the join code using
- Response: A success or error object is returned to the frontend.
- UI Event (
frontend/04-events.html):handleAvailabilityUpdate('add' | 'remove')is triggered by clicking "Add Me" or "Remove Me". - Payload Prep (
frontend/02d-schedule-availability.html):validateAvailabilityUpdate()checks for a selected team and valid initials.prepareUpdatePayload()groups the selected cells by week and creates aweeklyPayloadsarray.
- API Call (
frontend/02d-schedule-availability.html): It callsgoogle.script.run.updatePlayerAvailabilityForMultipleWeeks(teamId, action, payload). - Controller (
WebAppController.js):updatePlayerAvailabilityForMultipleWeeksreceives the call and passes it directly to the service function. - Business Logic (
AvailabilityManager.js): TheavailabilityManager_updatePlayerAvailabilityForMultipleWeeks_SERVICEfunction executes:- Checks user permissions.
- Loops through each week in the payload.
- Finds the correct week block on the team's sheet using
WeekBlockManager.js. - Reads the relevant cell range, updates the initials, and writes the data back. This is wrapped in
withProtectionBypassfromCellProtection.js. - Invalidates the script cache for the modified week blocks.
- Response: A success or error object is returned to the frontend, which then shows a status message.
- UI Request (
frontend/02c-team-ui.html):- For team logos:
loadTeamLogo()orbatchLoadLogos()is called - For generic images:
loadDriveImage()is called
- For team logos:
- API Call: Frontend calls
google.script.run.getTeamLogoAsBase64()orgoogle.script.run.getDriveImageAsBase64() - Controller (
WebAppController.js): Routes to appropriate ImageService function - Business Logic (
ImageService.js):- Extracts Google Drive file ID from URL
- Fetches file using
DriveApp.getFileById() - Converts to base64 using
Utilities.base64Encode() - Returns base64 data with MIME type
- Frontend Display: Creates data URL and updates
<img>src attribute - Caching: Frontend caches base64 data in memory for subsequent displays
- Type: Utility/Configuration (Foundation)
- Purpose: Central repository for all system-wide configurations, constants, and stateless utility functions.
- Key Components:
BLOCK_CONFIG: The master configuration object for the entire application (sheet schemas, layouts, team settings).- Date/Time, Validation, and Response-building utility functions.
handleError(): Centralized error logging utility.- NEW: Discord help image stored as base64 in
BLOCK_CONFIG.WEB_APP.DISCORD_HELP_IMAGE_URL
- Used By: Nearly all other
.jsfiles.
- Type: Manager (Security Core)
- Purpose: Centralized role detection, permission definition, and enforcement.
- Key Components:
ROLES,PERMISSIONS: Global constants defining all roles and permissions.getUserRole(): Detects a user's role with caching.userHasPermission(): Critical function for all security checks.getUserUIContext(): Builds the complete user context object.
- Dependencies (Calls):
PlayerDataManager.js,TeamDataManager.js.
- Type: Controller (Primary Entry Point)
- Purpose: Main entry point for
google.script.runcalls from the frontend and for serving the main HTML page. - Key Functions:
doGet(): Serves theindex.htmltemplate and injects initial data (userContextFromServer,BLOCK_CONFIG,ROLES).- Functions exposed to the frontend, such as
createNewTeam,joinTeamWithCode, andupdatePlayerAvailabilityForMultipleWeeks. - NEW:
getDriveImageAsBase64(),getTeamLogoAsBase64(),getMultipleTeamLogosAsBase64()
- Dependencies (Calls):
WebAppAPI.js,PlayerDataManager.js,AvailabilityManager.js,Administrator.js,ImageService.js.
- Type: Controller (API Service Layer)
- Purpose: Intermediate API layer that orchestrates complex business logic and prepares data for the frontend.
- Key Functions:
getUserContext(): Builds the initial user object.createNewTeamAndAddLeader(): Orchestrates the multi-step team creation process.checkForScheduleUpdates(): Handles the "smart-refresh" logic for the client.
- Used By:
WebAppController.js.
- Type: Manager (Core Business Logic)
- Purpose: All CRUD (Create, Read, Update, Delete) operations and business logic related to teams.
- Key Functions:
createTeam(),getTeamData(),archiveTeam(),validateJoinCode(). - Caching: Uses Script Cache for team data with keys like
teamData_TEAM_ID_incInactive_false - Dependencies (Calls):
PermissionManager.js,CellProtection.js,PlayerDataManager.js,MasterSheetManager.js,WeekBlockManager.js.
- Type: Manager (Core Business Logic)
- Purpose: Manages all player data, profiles, team membership, and team-specific attributes.
- Key Functions:
createPlayer(),getPlayerDataByEmail(),joinTeamByCode(),leaveTeam(),syncTeamPlayerData(). - Dependencies (Calls):
PermissionManager.js,TeamDataManager.js,AvailabilityManager.js,CellProtection.js.
- Type: Manager (Core Feature)
- Purpose: Manages all logic for reading and writing player availability on the schedule grids.
- Key Functions:
availabilityManager_updatePlayerAvailabilityForMultipleWeeks_SERVICE()am_getTeamSchedule()removePlayerInitialsFromSchedule()
- Caching: Uses Script Cache for availability data with keys like
scheduleData_SHEETNAME_YEAR_WWEEK - Dependencies (Calls):
PermissionManager.js,PlayerDataManager.js,TeamDataManager.js,WeekBlockManager.js,CellProtection.js.
- Type: Manager (Data Structure)
- Purpose: Manages the physical creation, discovery, and reading of the weekly data blocks on team sheets.
- Key Functions:
createSingleWeekBlock(),ensureWeekExists(),readWeekBlockData(). - Dependencies (Calls):
Configuration.js.
- Type: Manager (Admin Functions)
- Purpose: Houses high-privilege operations, currently focused on team leadership management.
- Key Functions:
core_adminSetTeamLeader(). - Dependencies (Calls):
PermissionManager.js,TeamDataManager.js,PlayerDataManager.js,CellProtection.js.
- Type: Service (Image Handling)
- Purpose: Handles all image operations including team logos and generic Google Drive images. Provides base64 conversion to bypass CORS issues.
- Key Functions:
uploadLogoFile(): Handles base64 file uploads for team logosfetchAndSaveTeamLogo(): Downloads and saves logos from URLsimageService_getTeamLogoAsBase64(): Converts team logo to base64imageService_getMultipleTeamLogosAsBase64(): Batch conversion for performanceimageService_getDriveImageAsBase64(): NEW - Generic Drive image to base64 conversion
- Dependencies (Calls):
Configuration.js,TeamDataManager.js.
CellProtection.js: Manages sheet protection and the criticalwithProtectionBypass()function for safe data writing.MasterSheetManager.js: Handles the one-time setup and teardown of the database sheets.ScheduledTasks.js: Manages automated background tasks, like provisioning new week blocks for teams.CacheManager.js: Manages theSYSTEM_CACHEsheet for pre-computed data like team rosters.
- Type: UI/UX
- Purpose: The complete user interface and all client-side logic.
- Key Architectural Patterns:
- Modular Structure:
index.htmlassembles the UI from partial files using<?!= include(...) ?>. - Ordered Scripts: Client-side JavaScript is loaded in a specific, numbered sequence to ensure dependencies are met, with
04-events.htmlloading last to bind all event handlers to the fully-rendered DOM. - Client-Side State: Global JS variables (
userContext,currentActiveTeamId,weekCache, etc.) are initialized in01-init.htmland hold the application's state.
- Modular Structure:
- Key Files:
index.html: The main template that includes all other parts.01-head-content.html: Contains all CSS and<head>elements.02-body-structure.html: Defines the application's static DOM layout.01-init.html: Initializes all global JavaScript variables. Must load first.02a-cache-navigation.html: Handles the client-side week cache andNext/Prevweek navigation.02b-grid-selection.html: Logic for selecting cells on the availability grids.02c-team-ui.html: Handles switching between teams, populating the user panel, and the initial "Join/Create Team" forms. NEW: Contains logo management functions (loadTeamLogo(),batchLoadLogos(),loadDriveImage())02d-schedule-availability.html: Renders the availability grids and handles the client-side part of updating availability.03-templates.html: Client-side logic for saving/loading availability templates.04-events.html: Attaches all DOM event listeners (e.g.,addEventListener). Must load last.
-
Script Cache (6 hours max)
- Team data:
teamData_{teamId}_incInactive_{boolean} - Availability data:
scheduleData_{sheetName}_{year}_W{week} - User roles:
userRole_{email} - Used for frequently accessed, medium-volatility data
- Team data:
-
SYSTEM_CACHE Sheet (permanent)
- Team metadata (ID, name, division, logo URL, isPublic)
- Team rosters as JSON (RosterJSON column)
- Pre-computed data for expensive "join" operations
- Updated when roster changes occur
-
Client-side Memory Cache (session)
- Week cache for navigation without server calls
- Logo cache (Map of teamId → base64 data)
- Selected cells for grid interactions
- Cleared on page refresh
appsscript.json: The manifest file. Thewebappsettings which setexecuteAstoUSER_DEPLOYINGandaccesstoANYONEare critical for the application to function correctly.README.js: High-level project documentation explaining the "why" behind the design choices.- Debug Suite (
/Debug*.js): A comprehensive testing suite for developers, accessible via a spreadsheet menu.