Skip to content

Feature/medal recommendation aid - #201

Draft
muzzy138 wants to merge 12 commits into
7Cav:mainfrom
muzzy138:feature/medal-recommendation-aid
Draft

Feature/medal recommendation aid#201
muzzy138 wants to merge 12 commits into
7Cav:mainfrom
muzzy138:feature/medal-recommendation-aid

Conversation

@muzzy138

Copy link
Copy Markdown

Adds the Medal Recommendation Aid to CavApps under /medalrecommendation for review.

The Medal Recommendation Aid is designed to help users correctly format and prepare medal recommendations using the current Awards and Decorations requirements. The app checks formatting and required information, but does not judge narrative quality, factual accuracy, or whether someone deserves the award. The person submitting the recommendation is still responsible for making sure the information is correct.

This is the CavApps migration of the original standalone Medal Recommendation Aid. The app has been moved into the existing Next.js/React structure and updated to use CavApps infrastructure where possible.

Included
Operation Medal recommendation worksheet
Service Medal recommendation worksheet
Individual and unit award support
Multiple recipients where applicable
Medal-specific citation generation and validation
Narrative character limits and formatting checks
CavApps roster integration for eligible recipients
Bulk recipient support for Service Unit Awards
Recommendation preview and BBCode output
How To Use page
Automated regression tests
Roster Integration

The Medal Aid uses the existing CavApps Combat and Reserve roster caches where possible.

A Medal-specific server endpoint was added to build the complete eligible roster. Supplemental ELOA and retired-member data is pulled separately and cached for one hour. I kept this separate from the existing shared CavApps cache manager to limit changes to other parts of CavApps.

Removed From the Standalone Version:

The old Feedback button and related feedback functions have been removed from the project. Feedback will instead go through the normal S6 ticket process.

All remaining Google Apps Script files and the old Google Apps Script roster bridge have also been removed. The Medal Aid now uses the CavApps server and 7Cav API instead of the previous Cloudflare/Google Apps Script setup.

Testing
43 automated tests passing
5 test files passing
Next.js production build completes successfully
New server controllers pass syntax checks
Tested locally through the CavApps Docker development environment

@SyniRon
SyniRon marked this pull request as draft August 11, 2026 02:31
@SyniRon

SyniRon commented Aug 11, 2026

Copy link
Copy Markdown
Collaborator

Setting this as draft while I work through the review. For starters @muzzy138 take a look at the failing prettier check and work that out please sir. Hit me up if you have questions.

@muzzy138

Copy link
Copy Markdown
Author

Setting this as draft while I work through the review. For starters @muzzy138 take a look at the failing prettier check and work that out please sir. Hit me up if you have questions.

Got it. Found the formatting issues and have Prettier passing on all of the files included in the PR now. I'm running the tests/build again to make sure nothing was affected, then I'll push the fix up.

@SyniRon

SyniRon commented Aug 11, 2026

Copy link
Copy Markdown
Collaborator

@muzzy138 As I've mentioned, I like the feature and want to find a path to getting it in. I have a few questions to start before I can keep reviewing the implementation.

  1. The other apps build their controls from client/components/ui (Button, Card, Input, Badge, Separator, Tooltip are all already in use), and get their unit taxonomy from reusableModules/BilletBank.jsx. This implementation hand-rolls both, and reference-data.js determines a billet's unit by pattern-matching the title string instead of using BilletBank's map. Was that divergence intentional? If so, what was the reason for it?

  2. reference-data.js is around 1,400 lines of award templates and eligibility rules. What source did you validate those values against? Smaller example of the same issue: the unit narrative field shows a 1,600-character limit, but the result warns at 1,400. Which limit is actually required by the SOP?

@muzzy138

muzzy138 commented Aug 11, 2026

Copy link
Copy Markdown
Author

@SyniRon appreciate the feedback and questions.

  1. That wasn't really intentional. Most of that came over from the original standalone Medal Aid, and during the migration I was trying to keep changes to the shared CavApps code as limited as possible. Because of that, I ended up carrying over some of the old UI and billet logic instead of using the existing client/components/ui controls and BilletBank.jsx like I should have.

  2. Reference-data.js stores the award rules/templates, defines the medal worksheets, and builds organization/unit choices from the roster data.

A breakdown of the larger sections:

const APP_RULES minimumUnitRecipients: 4 (This is straight from the wiki)
maximumUnitRecipients: 20, (is not an SOP requirement. That was originally put in during development/testing.)

const RANK_PRECEDENCE (Used when ordering the recipients above the narrative in the ticket post. This was put in place after reviewing ticket format rejections by S1)

const COMBAT_ROLE_CHOICES (This is not intended to be an all inclusive list or an eligibility rule. They are only suggestions/placeholders to help users understand some of the less obvious fields. These came largely from user feedback while I was testing the original app within my platoon.)

const Individual_Awards, Unit_Awards, Service_Award_Definitions (These are the worksheets and definitions. These are sourced straight from the Medals & Awards Wiki. They'll contain the criteria, eligibility, required wording, worksheet fields, and other award-specific requirements.)

validateServiceAwardDefinitions_() (checks if the service medal definitions are internally valid - basically a self-test for Service_Award_Definitions
-Protect award definitions
-Protect worksheet field definitions
-Protect template placeholders
-Protect conditional fields
-Protect service-period fields
-Confirm 13 individual + 2 unit awards)

buildOrganizationReference_() (might be redundant with CavApps functionality as this reads the roster billets, infers organizations, builds batt/co/plt lists and builds the support departments. It also deduplicates and sorts everything. I'm going to assume you would want this completely replaced by BilletBank.jsx rather than maintaining this separately)

For your exmaple:
To the best of my knowledge, and based on what I confirmed with the S1 Citations Lead, there is no defined character limit in the SOP. The limits in the app were a specific request from S1 Citations based on the amount of usable white space available on the citation templates. Unit citations have considerably more space available, which is why a higher character limit was set. Essentially these values are arbitrary and follow zero regulations.

Would you like me to push an update removing the 20-recipient cap and the character limits first?

I agree BilletBank.jsx should be used so the Medal Aid follows the same structure as the other CavApps, but that will be a more substantial rewrite. I just want to make sure I’m prioritizing the right changes for this review before I start digging into that.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants