MARKSMAN β Shooting Analytics Platform
Precision training analytics for competitive shooters, coaches, and military/tactical units.
A full-stack monorepo for recording, visualising, and analysing shooting performance.
Built with Next.js 15 , NestJS , Prisma , PostgreSQL , and a Python/OpenCV vision microservice.
π Live: marksmanspro.com Β |Β π± Mobile: Capacitor (iOS + Android)
Session management β Create, view, and delete training sessions with discipline, weapon, distance, and training mode metadata
Shot entry β Four input methods per session:
Click Target β Interactive 10-ring canvas; drag-and-drop shot placement with score preview
Manual Entry β Form-based shot entry with coordinate input
Photo / Camera β Upload or capture a target photo; OpenCV vision pipeline extracts shot coordinates automatically
File Import β Bulk import via CSV, JSON, or PDF
Live target canvas β Zoomable, pannable, exportable PNG; shot dots colour-coded by score ring; MPI crosshair overlay; coordinate direction indicators
Real-time updates β Socket.IO WebSocket pushes session.updated and feedback.added events to all connected clients
Session metrics β Average score, best shot, std deviation, group radius, MPI (x/y centroid), series averages
Overview dashboard β Cross-session trends, ring distribution, performance radar, group radius history, session history table
Score trend chart β AreaChart filterable by weapon type
Performance radar β 6-axis profile (Avg Score, Best Avg, X-Ring %, 10+ %, Consistency, 9+ %)
Session analysis β Sends shot data to Groq LLM (llama-3.3-70b-versatile) for natural language coaching insights
Structured output β Returns overall assessment, top 3 strengths, top 3 improvements, one drill recommendation
Free tier β Groq API: 14,400 req/day, no billing required
Role
Description
SHOOTER
Records sessions, adds shots, views own analytics, connects to a coach
COACH
Views connected shooters' sessions, posts feedback
SOLDIER
Combined access β sessions + analytics + AI Coach (tactical/military use)
Fixed bottom navigation bar on mobile (< 1024px); sidebar on desktop
Touch-friendly targets (min 44px), safe-area inset support (iOS notch)
Responsive layouts β single-column stacking on mobile, multi-column on desktop
Progressive column hiding in shot table on small screens
SVG favicon + multi-size PNG icons (16, 32, 48, 128, 180, 192, 512px)
manifest.webmanifest for installable PWA (standalone mode, amber theme)
Apple touch icon, mask-icon for Safari pinned tabs
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Browser / Client β
β Next.js 15 App Router :3000 β
β ββββββββββββββββββββ βββββββββββββββββ βββββββββββββββββββββ β
β β TargetCanvas β β Recharts β β AI Coach Chat β β
β β (10-ring SVG, β β (area, bar, β β (Groq streaming) β β
β β drag & drop) β β radar) β β β β
β ββββββββββββββββββββ βββββββββββββββββ βββββββββββββββββββββ β
ββββββββββββββββββββββββββββββββ¬ββββββββββββββββββββββββββββββββββββ
β HTTP REST + Socket.IO
ββββββββββββββββββββββββββββββββΌββββββββββββββββββββββββββββββββββββ
β NestJS API :3001 β
β AuthModule SessionsModule ShotsModule AnalyticsModule β
β CoachModule SuggestionsModule AiCoachModule GatewayModule β
ββββββββββββ¬βββββββββββββββββββββββββββββββββββ¬βββββββββββββββββββββ
β Prisma ORM β HTTP fetch /analyze
βΌ βΌ
ββββββββββββββββββββ ββββββββββββββββββββββββββββ
β PostgreSQL β β FastAPI Vision :8000 β
β shooting_ β β OpenCV pipeline β
β platform (DB) β β β shot coordinates β
ββββββββββββββββββββ ββββββββββββββββββββββββββββ
β Groq API
ββββββββββββΌββββββββββββββββ
β Groq Cloud (LLM) β
β llama-3.3-70b-versatile β
ββββββββββββββββββββββββββββ
/
βββ apps/
β βββ api/ NestJS backend
β β βββ prisma/
β β β βββ schema.prisma
β β β βββ seed.ts
β β β βββ migrations/
β β βββ src/
β β βββ auth/
β β βββ sessions/
β β βββ shots/
β β βββ analytics/
β β βββ suggestions/
β β βββ ai-coach/
β β βββ coach/
β β βββ gateway/
β β βββ prisma/
β β
β βββ web/ Next.js 15 frontend
β β βββ app/
β β β βββ layout.tsx
β β β βββ page.tsx β Marketing homepage
β β β βββ manifest.ts
β β β βββ dashboard/
β β β βββ sessions/
β β β βββ analytics/
β β β βββ ai-coach/
β β β βββ coach/
β β β βββ connect/
β β β βββ soldier/
β β β βββ auth/
β β βββ components/
β β β βββ AppShell.tsx
β β β βββ Sidebar.tsx
β β β βββ TopBar.tsx
β β β βββ BottomNav.tsx
β β β βββ TargetCanvas.tsx
β β β βββ AnalyticsCharts.tsx
β β β βββ LoadingScreen.tsx β Marketing loading animation
β β β βββ MarketingNav.tsx β Sticky nav with mobile drawer
β β β βββ MiniTargetCanvas.tsx β Hero shot map preview
β β β βββ ui/
β β βββ hooks/
β β β βββ useCountUp.ts β IntersectionObserver counter
β β βββ lib/
β β β βββ api.ts
β β β βββ auth.ts
β β β βββ chart-theme.ts β Recharts custom theme
β β β βββ use-mobile.ts
β β βββ public/
β β βββ og-image.png β 1200Γ630 OG image for social
β β βββ favicon.ico
β β
β βββ vision/ Python FastAPI microservice
β βββ main.py
β βββ requirements.txt
β
βββ packages/
β βββ shared-types/
β βββ index.ts
β
βββ CLAUDE.md β Claude Code design system guide
βββ DESIGN.md β Homepage audit & fix specs
βββ .env.example
βββ package.json
Aesthetic: Dark Luxury Precision β high-contrast readability in low-light environments.
Built for serious athletes, not casual consumers.
For full design system documentation used with Claude Code, see CLAUDE.md .
For the homepage-specific audit and fix specs, see DESIGN.md .
Token
Value
Usage
--bg-void
#080A0F
Page background
--bg-surface
#0E1118
Cards, sidebar
--bg-elevated
#161B26
Hover states, inputs
--bg-overlay
#1E2535
Modals, tooltips
--accent-primary
#F5A623
Amber β CTAs, active states, logo
--data-blue
#4FC3F7
Data values, 10-ring shots
--signal-red
#FF4D6D
Errors, low scores
--success
#00E5A0
Emerald β positive trends, 9-ring shots
Score
Color
Hex
β₯ 10.5 (X-ring)
Amber
#F5A623
β₯ 10.0
Blue
#4FC3F7
β₯ 9.0
Emerald
#00E5A0
< 9.0
Red
#FF4D6D
Role
Font
Weight
Usage
Headings
Rajdhani
600β700
All <h1> β <h3>
Body
DM Sans
400β500
Paragraphs, labels, nav
Data
JetBrains Mono
400β700
Scores, coordinates, KPIs
These issues have been identified and documented. Fix specs are in DESIGN.md .
Priority
Issue
Status
π΄ Critical
Stats counters show 0 β IntersectionObserver missing
Open
π΄ Critical
10-second loading screen with no progress feedback
Open
π΄ Critical
"Pricing" nav link 404s β no route exists
Open
π΄ Critical
Nav anchor links (#features, #how-it-works) don't scroll
Open
π High
Hero has no visual target/ring graphic
Open
π High
No mobile navigation menu on marketing page
Open
π High
Hero session card missing shot map visualization
Open
π High
No OG/meta image for social sharing
Open
π‘ Polish
Testimonials β no disclaimer for beta/representative quotes
Open
π‘ Polish
Feature card tier badges are inconsistent
Open
π‘ Polish
Country ticker doesn't pause on hover
Open
π‘ Polish
Footer status link is decorative, not functional
Open
Requirement
Version
Notes
Node.js
20+
npm
10+
Workspaces support
PostgreSQL
15+
Docker recommended
Python
3.11+
Vision service only
pip
latest
Vision service only
docker run -d \
--name shooting-db \
-e POSTGRES_PASSWORD=password \
-e POSTGRES_DB=shooting_platform \
-p 5433:5432 \
postgres:16
# Node packages (all workspaces)
npm install
# Python vision service
cd apps/vision && pip install -r requirements.txt && cd ../..
cp .env.example apps/api/.env
# Edit apps/api/.env with your DATABASE_URL, JWT_SECRET, GROQ_API_KEY
# Web app β defaults work without this file
echo ' NEXT_PUBLIC_API_URL=http://localhost:3001' > apps/web/.env.local
echo ' NEXT_PUBLIC_WS_URL=http://localhost:3001' >> apps/web/.env.local
npm run db:generate # Generate Prisma client
npm run db:migrate # Apply migrations
npm run db:seed # Seed demo data
WSL note: If db:seed fails due to native bcrypt mismatch, seed via Python:
# All three services concurrently
npm run dev
# Or individually:
npm run dev:api # NestJS β http://localhost:3001
npm run dev:web # Next.js β http://localhost:3000
npm run dev:vision # FastAPI β http://localhost:8000
All seed accounts use password Password123!
Email
Role
Access
shooter@example.com
SHOOTER
Sessions, shots, analytics, AI coach
coach@example.com
COACH
Shooters list, session review, feedback
soldier@example.com
SOLDIER
Sessions, shots, analytics, AI coach
Variable
Required
Description
Example
DATABASE_URL
Yes
Prisma PostgreSQL connection string
postgresql://postgres:password@127.0.0.1:5433/shooting_platform
JWT_SECRET
Yes
JWT signing secret (32+ chars)
9f3c7b1a8d6e4f2c9b0a7d3e5f6c8a1b
JWT_EXPIRES_IN
Yes
Token expiry
7d
PORT
No
API port (default 3001)
3001
CORS_ORIGINS
Yes
Comma-separated allowed origins
http://localhost:3000
GROQ_API_KEY
Yes
Free at console.groq.com
gsk_...
VISION_SERVICE_URL
No
FastAPI base URL
http://localhost:8000
NEXT_PUBLIC_API_URL
Yes
API URL for Next.js
http://localhost:3001
NEXT_PUBLIC_WS_URL
Yes
WebSocket URL
http://localhost:3001
All authenticated routes require Authorization: Bearer <token>.
Method
Path
Auth
Description
POST
/auth/register
β
Register (SHOOTER or COACH)
POST
/auth/login
β
Login β { access_token, user }
Method
Path
Auth
Description
POST
/sessions
JWT + SHOOTER/SOLDIER
Create session
GET
/sessions
JWT + SHOOTER/SOLDIER
List own sessions
GET
/sessions/:id
JWT + SHOOTER/SOLDIER/COACH
Get session with shots and feedback
DELETE
/sessions/:id
JWT + SHOOTER/SOLDIER
Soft-delete session
Method
Path
Auth
Description
POST
/shots/manual
JWT + SHOOTER/SOLDIER
Add shots via JSON body
POST
/shots/import
JWT + SHOOTER/SOLDIER
Upload CSV, JSON, or PDF
POST
/shots/photo
JWT + SHOOTER/SOLDIER
Upload target image β vision pipeline
Method
Path
Auth
Description
GET
/analytics/session/:id
JWT
Session metrics
GET
/analytics/overview
JWT + SHOOTER/SOLDIER
Cross-session overview
Method
Path
Auth
Description
POST
/ai-coach/analyze
JWT
Groq LLM session analysis
Method
Path
Auth
Description
POST
/coach/connect
JWT + SHOOTER
Request connection
PATCH
/coach/connect/:id/approve
JWT + COACH
Approve connection
GET
/coach/shooters
JWT + COACH
List connected shooters
POST
/coach/feedback
JWT + COACH
Post session feedback
Vision Service (FastAPI :8000)
Method
Path
Description
POST
/analyze
Analyse target image β shot coordinates
GET
/health
Health check
Connect to ws://localhost:3001 using Socket.IO.
Client β Server
Event
Payload
Description
joinSession
sessionId: string
Subscribe to live session updates
leaveSession
sessionId: string
Unsubscribe
Server β Client
Event
Payload
Description
session.updated
{ sessionId, newShotCount }
New shots added
feedback.added
{ sessionId, feedback }
Coach posted feedback
Average Score = Ξ£(scores) / n
MPI (x, y) = ( Ξ£(xi) / n , Ξ£(yi) / n )
β centroid of all shots
Group Radius = max over all pairs β( (xββxβ)Β² + (yββyβ)Β² )
β largest spread between any two shots
Std Deviation = β( Ξ£(score β avg)Β² / n )
Series Averages = chunk(shots, 10) β avg per chunk
Consistency = 10 β stdDev Γ 2 (clamped 0β10)
Coaching Suggestion Rules
Rule
Trigger
Suggestion
Sight drift left
MPI x < β0.5
Adjust sight right
Sight drift right
MPI x > +0.5
Adjust sight left
Grouping
Group radius > 5
Focus on trigger control
Endurance drop
Last series avg < first β 0.5
Add endurance training
Inconsistency
Std deviation > 1.0
Work on repeatable technique
POST /shots/import?sessionId=<id>
CSV (shotNumber,score,x,y):
1,9.5,-1.2,0.8
2,10.1,0.1,-0.2
JSON:
[{ "shotNumber" : 1 , "score" : 9.5 , "x" : -1.2 , "y" : 0.8 }]
PDF: One shot per line β shotNumber,score[,x,y]
Feature
SHOOTER
COACH
SOLDIER
Create session
β
β
β
Add shots
β
β
β
View own sessions
β
β
β
View analytics
β
β
β
AI Coach
β
β
β
Coach connection
β (initiate)
β (approve)
β
View shooter sessions
β
β
β
Post feedback
β
β
β
Weapons management
β
β
β
Field analytics
β
β
β
Fork and clone the repo
Follow the Design System and Homepage Specs
Run npm run dev to start all services
Open a PR against main
Built for precision. Β© 2026 Marksman.