Development Workflow¶
Last Updated: 2025-11-22
Overview¶
This guide outlines the development workflow for the AccessALI Customer Portal, from setting up your environment to deploying to production. Following this workflow ensures consistency, quality, and efficient collaboration across the development team.
Container-First Development
AccessALI uses a container-first approach with Docker as the primary development environment. This ensures consistency across all team members and production parity.
Daily Development Workflow¶
1. Starting Your Day¶
# Navigate to source directory
cd src
# Pull latest changes
git pull origin develop
# Start all services (if not already running)
pnpm docker:dev
# Check service status
pnpm docker:ps
Services Running
You should see 4 containers running:
app(Next.js on port 3000)postgres(PostgreSQL on port 5432)redis(Redis on port 6379)prisma-studio(Prisma Studio on port 5555)
2. Making Changes¶
Feature Development Flow¶
graph LR
A[Create Branch] --> B[Develop Feature]
B --> C[Test Locally]
C --> D[Type Check]
D --> E[Lint Code]
E --> F[Commit Changes]
F --> G[Push to GitHub]
G --> H[Create PR]
H --> I[Code Review]
I --> J[Merge to Develop]
Step-by-Step Process¶
1. Create Feature Branch
# Create and switch to new branch
git checkout -b feature/SP-123-user-dashboard
# Branch naming convention:
# feature/SP-XXX-description (new features)
# fix/SP-XXX-description (bug fixes)
# chore/SP-XXX-description (maintenance)
# docs/SP-XXX-description (documentation)
2. Develop Feature
Follow the layered architecture pattern:
// 1. Define database schema (if needed)
// File: prisma/schema.prisma
model Feature {
id String @id @default(cuid())
// ... fields
}
// 2. Run migration
// Terminal: pnpm docker:db:migrate
// 3. Create repository
// File: src/lib/repositories/feature-repository.ts
export async function createFeature(data: FeatureInput) {
return prisma.feature.create({ data })
}
// 4. Create use case
// File: src/lib/use-cases/feature.ts
export async function createFeatureUseCase(userId: string, data: FeatureInput) {
// Business logic here
return createFeature(data)
}
// 5. Create server action
// File: src/app/actions/feature.ts
'use server'
export async function createFeatureAction(data: unknown) {
const session = await auth()
if (!session) throw new Error('Unauthorized')
const validated = featureSchema.parse(data)
return createFeatureUseCase(session.user.id, validated)
}
// 6. Create page
// File: src/app/feature/page.tsx
export default async function FeaturePage() {
const data = await getFeatureData()
return <FeatureView data={data} />
}
3. Test Locally
# Check logs
pnpm docker:logs:app
# Access application
open http://localhost:3000
# Check database
pnpm docker:db:studio
# Opens http://localhost:5555
4. Type Check
5. Lint Code
6. Commit Changes
# Stage files
git add .
# Commit with conventional commit message
git commit -m "feat(dashboard): add user statistics widget
- Add statistics component
- Implement data fetching
- Add responsive layout
Closes SP-123"
Commit Message Format:
Types: feat, fix, docs, style, refactor, test, chore
Examples:
feat(auth): implement OAuth login
fix(payments): resolve payment calculation error
docs(readme): update installation instructions
chore(deps): upgrade Next.js to 15.5.6
7. Push to GitHub
8. Create Pull Request
Use GitHub UI or CLI:
# Using GitHub CLI
gh pr create \
--title "feat(dashboard): Add user statistics widget" \
--body "## Summary
- Implements user statistics widget
- Fetches data from use case layer
- Responsive design with shadcn/ui
## Testing
- [ ] Verified on desktop (Chrome, Safari)
- [ ] Verified on mobile
- [ ] Unit tests passing
- [ ] Type check passing
Closes #123"
3. Code Review Process¶
PR Review Checklist¶
Reviewer Checklist:
- Code Quality
- Follows layered architecture
- No code duplication
- Clear variable/function names
-
Appropriate comments where needed
-
Functionality
- Feature works as described
- No regressions
- Edge cases handled
-
Error handling implemented
-
Security
- Input validation with Zod
- Authorization checks in place
- No sensitive data exposed
-
SQL injection prevented
-
Performance
- Efficient database queries
- Proper indexing
- No N+1 queries
-
Appropriate caching
-
Testing
- Type check passes
- Lint passes
- Manual testing completed
Requesting Changes¶
### Feedback
**Architecture:**
- Move business logic from server action to use case layer
- Create dedicated repository method instead of inline Prisma query
**Security:**
- Add Zod validation for user input
- Implement authorization check before data access
**Code Quality:**
- Extract magic numbers to constants
- Add JSDoc comments for complex logic
**Performance:**
- Use database transaction for multiple operations
- Add index on `userId` column
4. Merging¶
Once approved:
# Update branch with latest develop
git checkout develop
git pull origin develop
git checkout feature/SP-123-user-dashboard
git merge develop
# Resolve conflicts if any
# Then push
git push
# Merge via GitHub UI
# Choose "Squash and merge" for clean history
Database Changes¶
Adding New Models¶
1. Update Schema
// prisma/schema.prisma
model NewModel {
id String @id @default(cuid())
field1 String
field2 Int?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@index([field1])
@@map("new_models")
}
2. Create Migration
3. Verify Migration
4. Commit Migration
Migration Best Practices
- Always review generated SQL before committing
- Test migrations in development first
- Never edit existing migration files
- Use
prisma migrate deployin production
Modifying Existing Models¶
Safe Changes: - Adding optional fields - Adding indexes - Renaming fields (with @map)
Breaking Changes: - Removing fields (requires data migration) - Changing field types - Making fields required
Data Migration Example:
// Step 1: Add new optional field
model User {
newField String?
}
// Step 2: Run migration
// Step 3: Backfill data
// Step 4: Make field required in new migration
model User {
newField String
}
Testing Strategy¶
Manual Testing¶
# 1. Start environment
pnpm docker:dev
# 2. Test feature in browser
open http://localhost:3000
# 3. Check different scenarios
# - Happy path
# - Error cases
# - Edge cases
# - Different user roles
# 4. Test on different devices
# - Desktop (Chrome, Safari, Firefox)
# - Mobile (iOS Safari, Chrome)
# - Tablet
Type Checking¶
Linting¶
Unit Testing (Planned)¶
Environment Management¶
Environment Files¶
.env.docker # Docker development (committed)
.env.local # Local development (ignored)
.env.production # Production (Vercel)
Adding Environment Variables¶
1. Add to .env.docker
2. Add to Vercel
# Using Vercel CLI
vercel env add NEW_VARIABLE production
# Or via Vercel Dashboard
# Project Settings → Environment Variables
3. Update Documentation
Update relevant docs with new variable and its purpose.
Common Tasks¶
Viewing Logs¶
# All services
pnpm docker:logs
# Specific service
pnpm docker:logs:app
pnpm docker:logs:db
# Follow logs
pnpm docker:logs:app -f
Database Operations¶
# Access Prisma Studio
pnpm docker:db:studio
# Run migrations
pnpm docker:db:migrate
# Seed database
pnpm docker:db:seed
# Reset database (destructive!)
pnpm docker:db:reset
Container Management¶
# Start services
pnpm docker:dev
# Stop services
pnpm docker:down
# Restart service
pnpm docker:restart:app
# View running containers
pnpm docker:ps
# Access container shell
pnpm docker:shell
# Clean everything (nuclear option)
pnpm docker:clean
Debugging¶
View Application Logs:
Access Container Shell:
Database Debugging:
# Access database shell
pnpm docker:db:shell
# Inside PostgreSQL
\dt # List tables
\d users # Describe users table
SELECT * FROM users LIMIT 5;
Troubleshooting¶
Port Already in Use¶
# Find process using port 3000
lsof -ti:3000
# Kill process
kill -9 $(lsof -ti:3000)
# Or change port in docker-compose.yml
Container Won't Start¶
Database Connection Issues¶
# Check PostgreSQL is running
pnpm docker:ps
# Restart database
pnpm docker:restart:db
# Check connection string
cat .env.docker | grep DATABASE_URL
Hot Reload Not Working¶
Best Practices¶
Code Organization¶
✅ DO:
- Follow layered architecture
- Use absolute imports (@/)
- One component per file
- Collocate related files
- Keep files under 300 lines
❌ DON'T:
- Bypass architecture layers
- Use relative imports (../../)
- Create God files
- Duplicate code
- Commit commented code
Git Workflow¶
✅ DO: - Pull before creating branch - Commit often with clear messages - Keep PRs focused and small - Resolve merge conflicts promptly - Delete branches after merge
❌ DON'T: - Commit directly to develop/main - Create massive PRs - Force push to shared branches - Commit sensitive data - Leave stale branches
Performance¶
✅ DO: - Use Server Components by default - Implement proper database indexes - Cache expensive operations - Optimize images with Next.js Image - Use dynamic imports for heavy components
❌ DON'T: - Use Client Components unnecessarily - Make N+1 database queries - Fetch data in loops - Load all data upfront - Skip performance testing
Related Documentation¶
- Docker Development - Docker setup and commands
- Project Structure - File organization
- Coding Conventions - Code style guide
- Error Handling - Error patterns
Next Steps¶
- Set up your Docker environment
- Review coding conventions
- Explore project structure
- Check error handling guide