modularity-maturity-assessor
npx skills add https://github.com/gilbertopsantosjr/fullstacknextjs --skill modularity-maturity-assessor
Agent 安装分布
Skill 文档
Modularity Maturity Assessor (Next.js + DynamoDB)
Expert in evaluating modular architecture compliance and maturity levels based on the 10 foundational principles, with enhanced detection for modern patterns like service layer design, runtime-agnostic code, and explicit communication contracts.
Technology Stack Context
| Component | Technology |
|---|---|
| Framework | Next.js 15+ / React 19+ |
| Database | DynamoDB (single-table design) |
| ORM | OneTable |
| Server Actions | ZSA (Zod Server Actions) |
| Validation | Zod schemas |
| Testing | Vitest |
| Deployment | SST (Serverless Stack) |
Critical Principles (Highest Weight)
These principles have the highest impact on architecture maturity:
| Rank | Principle | Weight | Why Critical |
|---|---|---|---|
| 1 | State Isolation (P8) | 1.5x | Most frequently violated, causes data integrity issues |
| 2 | Well-Defined Boundaries (P1) | 1.2x | Foundation for all other principles |
| 3 | Explicit Communication (P5) | 1.2x | Prevents coupling via service layer enforcement |
| 4 | Deployment Independence (P7) | 1.0x | Enables runtime flexibility (Next.js + Lambda) |
When to Use This Skill
- User asks for architecture assessment, compliance check, or maturity evaluation
- User mentions “modularity”, “architecture quality”, or “principle compliance”
- User requests verification of feature boundaries or design patterns
- Proactively after major refactoring or feature creation to verify compliance
- Before production deployments to catch compliance regressions
- After adding cross-feature dependencies to verify proper communication patterns
Assessment Process
Phase 1: Load Documentation Context
Load documents in this order as needed:
- Always start with:
docs/ARCHITECTURE-OVERVIEW.md(navigation hub) - For state isolation checks:
docs/STATE-ISOLATION.md(most critical violations) - For feature structure:
docs/MODULAR-PRINCIPLES.md(principles 1-7) - For implementation patterns:
docs/CODING-PATTERNS.md - For DynamoDB patterns:
docs/DYNAMODB-DESIGN.md
Phase 2: Run Detection Commands
Critical – State Isolation (Principle 8): HIGHEST PRIORITY
# Cross-feature DAL imports (MOST CRITICAL)
echo "=== Cross-Feature DAL Imports (P0) ==="
grep -r "from '@/features/[^']*dal'" src/features/ | \
awk -F: '{
match($1, /features\/([^/]+)/, feat);
match($2, /features\/([^/]+)\/dal/, imported);
if (feat[1] != imported[1] && imported[1] != "") {
print "VIOLATION: " $1 " imports from " imported[1] "/dal"
}
}'
# DynamoDB key patterns without feature prefix
echo "=== DynamoDB Key Patterns ==="
grep -E "(pk|sk):" src/features/database/db-schema.ts
Deployment Independence (Principle 7) – Runtime Agnostic:
# Check for 'server-only' in DAL files (P0 - breaks Lambda)
echo "=== 'server-only' in DAL (P0) ==="
grep -l "server-only" src/features/*/dal/*.ts 2>/dev/null
# Check for Next.js-specific imports in DAL/service (P1)
echo "=== Next.js imports in DAL/Service (P1) ==="
grep -r "from 'next" src/features/*/dal/ src/features/*/service/ 2>/dev/null
Explicit Communication (Principle 5) – Service Layer:
# Check for missing service layers when features are accessed externally
echo "=== Features Without Service Layer (P1) ==="
for dir in src/features/*/; do
name=$(basename $dir)
external_imports=$(grep -r "from '@/features/$name'" src/features/ 2>/dev/null | grep -v "src/features/$name" | wc -l)
if [ "$external_imports" -gt 0 ]; then
if [ ! -d "$dir/service" ]; then
echo "WARNING: $name has $external_imports external imports but no service layer"
fi
fi
done
# Check for DAL exports in index.ts (violation)
echo "=== DAL Exports in index.ts (P1) ==="
grep -l "from.*dal" src/features/*/index.ts 2>/dev/null
Well-Defined Boundaries (Principle 1):
# Check what's exported from each feature
echo "=== Feature Exports ==="
for dir in src/features/*/; do
name=$(basename $dir)
if [ -f "$dir/index.ts" ]; then
echo "=== $name ==="
grep "export" $dir/index.ts
fi
done
RepositoryResult Pattern:
# DAL files without RepositoryResult (P1)
echo "=== DAL Without RepositoryResult (P1) ==="
grep -L "RepositoryResult" src/features/*/dal/*.ts 2>/dev/null | grep -v test | grep -v index
Lean Server Actions:
# Check action file sizes (should be <50 lines)
echo "=== Action File Sizes ==="
find src/features/*/actions -name "*.ts" ! -name "index.ts" -exec wc -l {} \; 2>/dev/null | \
awk '$1 > 50 {print "WARNING: " $2 " has " $1 " lines (>50)"}'
# Check for ZSA pattern usage
echo "=== ZSA Pattern Usage ==="
grep -l "authedProcedure\|publicProcedure" src/features/*/actions/*.ts 2>/dev/null | wc -l
Testing (Vitest):
# Check for test files
echo "=== Test Coverage ==="
for dir in src/features/*/dal/; do
feature=$(echo $dir | sed 's|src/features/||' | sed 's|/dal/||')
dal_count=$(ls $dir/*.ts 2>/dev/null | grep -v test | grep -v index | wc -l)
test_count=$(ls $dir/*.test.ts 2>/dev/null | wc -l)
echo "$feature: $test_count tests for $dal_count DAL files"
done
# Check for cross-feature DAL imports in tests (violation)
echo "=== Cross-Feature DAL in Tests (P0) ==="
grep -r "from '@/features/[^']*dal'" src/features/**/*.test.ts 2>/dev/null | \
awk -F: '{
match($1, /features\/([^/]+)/, feat);
match($2, /features\/([^/]+)\/dal/, imported);
if (feat[1] != imported[1] && imported[1] != "") {
print "VIOLATION: " $1 " imports from " imported[1] "/dal"
}
}'
Maturity Scoring
| Principle | Score | Weight | Weighted Score | Notes |
|---|---|---|---|---|
| 1. Boundaries | X/10 | 1.2 | X | [Brief note] |
| 2. Composability | X/10 | 0.8 | X | [Brief note] |
| 3. Independence | X/10 | 1.0 | X | [Brief note] |
| 4. Individual Scale | X/10 | 0.6 | X | [Brief note] |
| 5. Explicit Communication | X/10 | 1.2 | X | [Brief note] |
| 6. Replaceability | X/10 | 0.8 | X | [Brief note] |
| 7. Deployment Independence | X/10 | 1.0 | X | [Brief note] |
| 8. State Isolation | X/10 | 1.5 | X | [Brief note] CRITICAL |
| 9. Observability | X/10 | 0.9 | X | [Brief note] |
| 10. Fail Independence | X/10 | 0.9 | X | [Brief note] |
| TOTAL | 10.0 | X/100 |
Scoring Guidelines
10/10 – Excellent: Full compliance, best practices followed, service layers where needed 8-9/10 – Good: Strong compliance, minor improvements possible 6-7/10 – Acceptable: Partial compliance, some violations, missing service layers 4-5/10 – Needs Improvement: Multiple violations, cross-feature DAL access detected 1-3/10 – Critical: Major violations, state isolation broken, immediate action required
Automatic Fail Conditions
The following violations automatically cap the overall score:
| Violation | Max Score | Reason |
|---|---|---|
| Cross-feature DAL imports | 40/100 | Independence completely broken |
'server-only' in DAL |
50/100 | Deployment independence broken |
| Cross-feature DAL in tests | 55/100 | Test isolation broken |
| Missing service layer (when needed) | 65/100 | Explicit communication violated |
| DAL exports in index.ts | 70/100 | Boundaries not well-defined |
| DAL without RepositoryResult | 75/100 | Error handling pattern missing |
Common Pitfalls to Check
P0 – Critical (Block Deployment)
- Cross-Feature DAL Imports – MOST CRITICAL
'server-only'in DAL – Breaks Lambda deployment- Cross-Feature DAL in Tests – Test isolation violation
- DynamoDB Keys Without Feature Prefix – Data isolation risk
P1 – High (Fix in Current Sprint)
- Missing Service Layer (when other features access)
- DAL Without RepositoryResult – Inconsistent error handling
- Fat Server Actions (>50 lines) – Business logic leaking
- DAL Exports in index.ts – Boundaries violated
- Next.js Imports in DAL/Service – Runtime coupling
P2 – Medium (Fix Soon)
- Missing Tests for DAL – Coverage gaps
- Services Without JSDoc – Documentation gaps
- Inconsistent Naming (snake_case DAL, kebab-case actions)
- Missing Zod Schemas – Validation gaps
P3 – Low (Nice to Have)
- Missing Logging in DAL – Observability gaps
- No Error Codes – Debugging harder
- Missing Type Exports – Consumer experience
Detection Commands Summary
Run All Critical Checks
#!/bin/bash
# architecture-check.sh
echo "========================================"
echo "Architecture Compliance Check"
echo "========================================"
FAILED=0
# P0: Cross-feature DAL imports
echo -e "\n[P0] Cross-Feature DAL Imports..."
VIOLATIONS=$(grep -r "from '@/features/" src/features/ 2>/dev/null | \
grep "/dal'" | \
awk -F: '{
match($1, /features\/([^/]+)/, feat);
match($2, /features\/([^/]+)\/dal/, imported);
if (feat[1] != imported[1] && imported[1] != "") {
print " " $1
}
}')
if [ ! -z "$VIOLATIONS" ]; then
echo "FAIL: Cross-feature DAL imports found:"
echo "$VIOLATIONS"
FAILED=1
else
echo "PASS"
fi
# P0: 'server-only' in DAL
echo -e "\n[P0] 'server-only' in DAL..."
SERVER_ONLY=$(grep -l "server-only" src/features/*/dal/*.ts 2>/dev/null)
if [ ! -z "$SERVER_ONLY" ]; then
echo "FAIL: 'server-only' found in DAL:"
echo "$SERVER_ONLY"
FAILED=1
else
echo "PASS"
fi
# P0: Cross-feature DAL in tests
echo -e "\n[P0] Cross-Feature DAL in Tests..."
TEST_VIOLATIONS=$(grep -r "from '@/features/" src/features/**/*.test.ts 2>/dev/null | \
grep "/dal'" | \
awk -F: '{
match($1, /features\/([^/]+)/, feat);
match($2, /features\/([^/]+)\/dal/, imported);
if (feat[1] != imported[1] && imported[1] != "") {
print " " $1
}
}')
if [ ! -z "$TEST_VIOLATIONS" ]; then
echo "FAIL: Cross-feature DAL imports in tests:"
echo "$TEST_VIOLATIONS"
FAILED=1
else
echo "PASS"
fi
# P1: DAL exports in index.ts
echo -e "\n[P1] DAL Exports in index.ts..."
DAL_EXPORTS=$(grep -l "from.*dal" src/features/*/index.ts 2>/dev/null)
if [ ! -z "$DAL_EXPORTS" ]; then
echo "WARNING: DAL exported in index.ts:"
echo "$DAL_EXPORTS"
else
echo "PASS"
fi
# P1: RepositoryResult pattern
echo -e "\n[P1] RepositoryResult Pattern..."
NO_RESULT=$(grep -L "RepositoryResult" src/features/*/dal/*.ts 2>/dev/null | grep -v test | grep -v index)
if [ ! -z "$NO_RESULT" ]; then
echo "WARNING: DAL files without RepositoryResult:"
echo "$NO_RESULT"
else
echo "PASS"
fi
# P1: Service layer check
echo -e "\n[P1] Service Layer Coverage..."
for dir in src/features/*/; do
name=$(basename $dir)
external_imports=$(grep -r "from '@/features/$name'" src/features/ 2>/dev/null | grep -v "src/features/$name" | wc -l | tr -d ' ')
if [ "$external_imports" -gt 0 ]; then
if [ ! -d "${dir}service" ]; then
echo "WARNING: $name has $external_imports external imports but no service layer"
fi
fi
done
echo "DONE"
# Summary
echo -e "\n========================================"
if [ $FAILED -eq 1 ]; then
echo "RESULT: FAILED - Critical violations found"
exit 1
else
echo "RESULT: PASSED - No critical violations"
exit 0
fi
CI/CD Integration
GitHub Actions Workflow
name: Architecture Compliance
on: [push, pull_request]
jobs:
compliance-check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: P0 - Cross-Feature DAL Imports
run: |
VIOLATIONS=$(grep -r "from '@/features/" src/features/ 2>/dev/null | \
grep "/dal'" | \
awk -F: '{
match($1, /features\/([^/]+)/, feat);
match($2, /features\/([^/]+)\/dal/, imported);
if (feat[1] != imported[1] && imported[1] != "") {
print $1
}
}')
if [ ! -z "$VIOLATIONS" ]; then
echo "Cross-feature DAL imports found:"
echo "$VIOLATIONS"
exit 1
fi
echo "No cross-feature DAL imports"
- name: P0 - server-only in DAL
run: |
SERVER_ONLY=$(grep -l "server-only" src/features/*/dal/*.ts 2>/dev/null || true)
if [ ! -z "$SERVER_ONLY" ]; then
echo "'server-only' found in DAL:"
echo "$SERVER_ONLY"
exit 1
fi
echo "No 'server-only' in DAL"
- name: P0 - Cross-Feature DAL in Tests
run: |
VIOLATIONS=$(grep -r "from '@/features/" src/features/**/*.test.ts 2>/dev/null | \
grep "/dal'" | \
awk -F: '{
match($1, /features\/([^/]+)/, feat);
match($2, /features\/([^/]+)\/dal/, imported);
if (feat[1] != imported[1] && imported[1] != "") {
print $1
}
}' || true)
if [ ! -z "$VIOLATIONS" ]; then
echo "Cross-feature DAL in tests:"
echo "$VIOLATIONS"
exit 1
fi
echo "No cross-feature DAL in tests"
- name: P1 - RepositoryResult Pattern
run: |
NO_RESULT=$(grep -L "RepositoryResult" src/features/*/dal/*.ts 2>/dev/null | grep -v test | grep -v index || true)
if [ ! -z "$NO_RESULT" ]; then
echo "DAL files without RepositoryResult:"
echo "$NO_RESULT"
echo "::warning::Some DAL files missing RepositoryResult pattern"
fi
- name: Run Tests
run: npx vitest run
Pre-Commit Hook
Add to .git/hooks/pre-commit:
#!/bin/bash
set -e
echo "Running Architecture Compliance Checks..."
# P0: Cross-feature DAL imports
VIOLATIONS=$(grep -r "from '@/features/" src/features/ 2>/dev/null | \
grep "/dal'" | \
awk -F: '{
match($1, /features\/([^/]+)/, feat);
match($2, /features\/([^/]+)\/dal/, imported);
if (feat[1] != imported[1] && imported[1] != "") { print $1 }
}')
if [ ! -z "$VIOLATIONS" ]; then
echo "BLOCKED: Cross-feature DAL imports found"
echo "$VIOLATIONS"
exit 1
fi
# P0: 'server-only' in DAL
SERVER_ONLY=$(grep -l "server-only" src/features/*/dal/*.ts 2>/dev/null || true)
if [ ! -z "$SERVER_ONLY" ]; then
echo "BLOCKED: 'server-only' in DAL"
echo "$SERVER_ONLY"
exit 1
fi
echo "Architecture checks passed"
Maturity Level Definitions
Immature (0-40/100)
- Critical principle violations
- Cross-feature DAL imports
- No service layers
'server-only'in DAL- Multiple P0 issues
Developing (41-65/100)
- Some boundaries defined
- Partial service layer coverage
- Some DAL functions missing RepositoryResult
- Can deploy with monitoring
Mature (66-85/100)
- Strong boundaries
- Service layers where needed
- RepositoryResult throughout
- Runtime-agnostic DAL
- Good test coverage
Advanced (86-100/100)
- Excellent compliance
- Best practices throughout
- Zero critical violations
- Full test coverage
- Only optimization opportunities
Best Practices
- Be Thorough: Check every feature, don’t skip any
- Be Specific: Always provide file paths for violations
- Be Actionable: Every violation needs a clear fix
- Be Evidence-Based: Back claims with detection command output
- Prioritize Correctly: P0 violations are always blockers
- Reference Documentation: Link to specific doc sections for each finding
- Run All Commands: Don’t skip detection commands
Notes
- Always prioritize State Isolation (Principle 8) as it’s the most critical
- Detection commands are mandatory, not optional
- Every finding must reference specific documentation
- Be constructive: show both the problem AND the solution
- Consider running this assessment after major refactoring or before production releases
- Cross-feature DAL imports are the #1 violation to catch
Sample Assessment Output
# Architecture Maturity Assessment
**Date**: 2025-01-15
**Scope**: All features in src/features/
## Executive Summary
**Overall Score**: 72/100 (Mature)
**Critical Violations**: 0
**High Priority Issues**: 3
**Medium Priority Issues**: 5
## Findings
### P0 - Critical (None)
No critical violations found.
### P1 - High Priority
1. **Missing Service Layer in `billing` feature**
- Location: `src/features/billing/`
- Issue: `accounts` feature imports from `billing` but no service layer exists
- Fix: Create `src/features/billing/service/billing-service.ts`
2. **DAL Without RepositoryResult**
- Location: `src/features/notifications/dal/send_email.ts`
- Issue: Function throws instead of returning RepositoryResult
- Fix: Wrap in try/catch, return RepositoryResult<void>
3. **Fat Server Action**
- Location: `src/features/accounts/actions/create-account.ts` (78 lines)
- Issue: Business logic in action handler
- Fix: Extract to DAL function
### P2 - Medium Priority
1. Missing tests for `billing` DAL (0/5 coverage)
2. Missing JSDoc on `accountsService` methods
3. Inconsistent naming in `notifications/dal/SendEmail.ts` (should be snake_case)
4. Missing Zod schema for `UpdateBillingInput`
5. No error codes in `notifications` DAL errors
## Recommendations
1. **Immediate**: Create billing service layer (blocks next deployment)
2. **This Sprint**: Add RepositoryResult to notifications DAL
3. **This Sprint**: Refactor fat create-account action
4. **Next Sprint**: Add billing DAL tests
5. **Backlog**: Standardize naming conventions
References
- Architecture Overview:
docs/ARCHITECTURE-OVERVIEW.md - State Isolation:
docs/STATE-ISOLATION.md - Coding Patterns:
docs/CODING-PATTERNS.md - DynamoDB Design:
docs/DYNAMODB-DESIGN.md - Testing Patterns:
docs/TESTING-PATTERNS.md