Yes you're on the right track, you'll either use triggers and/or check constraints to do this.
Also, PostgresQL has a very flexible type system. Make sure to select the most appropriate, restrictive types. You can even define custom types yourself.
- UNIQUE constraints
- CHECK Constraints
- FOREIGN KEY constraints - tutorial
- Triggers, which can call helper functions written in any supported procedural language. Triggers can
RAISE EXCEPTION to abort a transaction.
- Domain Types
- EXCLUSION constraints in 9.2 and newer
- Multi-column
PRIMARY KEYs
- Partial
UNIQUE indexes
Note that instead of using varchar(length) you're usually better off using text and a check constraint.