Real-World Project, Deployment, and Best Practices
The Real-World Project
Everything so far combines into a complete User Management / HR-style application: user authentication, role-based access, CRUD, REST APIs, validation, security, and performance work together across the full stack.
Domain Model
class User {
String username
String email
String password
Boolean enabled = true
Date dateCreated
Date lastUpdated
Department department
static constraints = {
username blank: false, unique: true
email email: true, unique: true
password blank: false
}
}
class Role {
String authority
static constraints = { authority blank: false, unique: true }
}
class UserRole {
User user
Role role
static mapping = { id composite: ['user', 'role']; version false }
}
class Department {
String name
static constraints = { name blank: false }
}Business Logic in Services
class UserService {
def passwordEncoder
@Transactional
def registerUser(Map params) {
def user = new User(params)
user.password = passwordEncoder.encode(user.password)
user.save(failOnError: true)
assignRole(user, Role.findByAuthority("ROLE_USER"))
user
}
}Passwords are always hashed with BCrypt, never stored in plain text.
Thin Controllers and GSP
Controllers accept input, delegate to services, and point at GSP views. Views iterate the model with g:each, submit with g:form, and surface errors with g:hasErrors.
Spring Security Integration
// build.gradle
implementation "org.grails.plugins:spring-security-core:6.1.0"Generate the security classes, then configure static rules:
grails.plugin.springsecurity.controllerAnnotations.staticRules = [
[pattern: '/', access: ['permitAll']],
[pattern: '/login/**', access: ['permitAll']],
[pattern: '/admin/**', access: ['ROLE_ADMIN']],
[pattern: '/**', access: ['ROLE_USER']]
]Deployment
Build options:
grails build # runnable JAR + embedded Tomcat
grails war # WAR for an external TomcatProduction checklist:
- dbCreate: none in production; manage schema with Flyway/Liquibase.
- Externalize secrets through environment variables.
- Use HTTPS everywhere and BCrypt for passwords.
- Dockerize with eclipse-temurin:17-jdk for consistent environments.
- Configure Logback, health checks, and automated backups.
Monitoring and Maintenance
- Log business events (info) and failures (error); debug only in development.
- Expose /actuator/health for load balancers.
- Track response times, memory, and database performance.
- Automate backups and test restoration.
- Schedule dependency updates and security patches.
Best Practices Quick Reference
- Thin controllers, fat services, focused domain classes.
- Prefer where queries, paginate always, avoid eager fetching.
- BCrypt passwords, role-based authorization, never trust input.
- Measure before optimizing; cache wisely; async for heavy tasks.
- Unit test logic, integration test critical flows, automate in CI.
- Use migrations, externalize config, monitor continuously.
Next Steps
Go further with: Grails microservices, advanced Spring Security (OAuth2/Keycloak), React/Vue frontends, migrating to Grails 7, and performance tuning at scale. Learn conventions deeply, respect simplicity, write tests early, and optimize only when needed.
Key Points
- A full-stack Grails app ties every concept together.
- Hash passwords, secure APIs, and never trust input.
- Use JAR/WAR builds plus Docker for deployment.
- Monitor, back up, and migrate schema like a production service.